Fetch Mirrors

The command to fetch an image from the Docker image repository is docker pull. the command format is:

$ docker pull [options] [Docker Registry address[:port number]/] repository name[:label] 

The specific options can be seen with the docker pull –help command, here we talk about the format of the image name.

Docker image repository address: the format of the address is usually <domain name/IP>[:port number]. The default address is Docker Hub (docker.io).
Repository name: As mentioned before, the repository name here is a two-part name, i.e. <username>/<software name>. For Docker Hub, if no username is given, it defaults to library, which is the official image.

For example:

$ docker pull ubuntu:18.04
18.04: Pulling from library/ubuntu
92dc2a97ff99: Pull complete
be13a9d27eb8: Pull complete
c8299583700a: Pull complete
Digest: sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26
Status: Downloaded newer image for ubuntu:18.04
docker.io/library/ubuntu:18.04 

The above command does not give the address of the Docker image repository, so it will pull the image from the Docker Hub (docker.io). The name of the image is ubuntu:18.04, so we’ll fetch the image labelled 18.04 from the official library/ubuntu repository. The last line of the output of the docker pull command gives the full name of the image, i.e.: docker.io/library/ubuntu:18.04.

The download process shows the concept of tiered storage that we mentioned earlier, where the image is made up of multiple tiers of storage. The download also goes through layers, not a single file. The download process gives the first 12 bits of the ID of each tier. After the download is complete, a full sha256 digest of the image is given to ensure consistency of the download.

When using the above commands, you may find that the layer IDs and sha256 summaries you see are not the same as the ones you see here. This is because the official mirrors are always being maintained, and any new bugs, or version updates, will be fixed and then released under the original tag, which ensures that any user using this tag can get a safer, more stable mirror.

Run Mirrors

Once we have an image, we can start and run a container based on that image. Using ubuntu:18.04 as an example, if we want to start the bash inside and interact with it, we can run the following command.

$ docker run -it --rm ubuntu:18.04 bash

root@e7009c6ce357:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.1 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic 

docker run is the command to run the container. We’ll briefly explain the parameters used above here.

  • -it: These are two arguments, one for -i: interactive and one for -t terminal. We’re going to go into bash execute some commands and see the results, so we need an interactive terminal.
  • rm: This parameter means that the container will be deleted along with it when it exits. By default, exiting containers are not deleted immediately for troubleshooting purposes unless you manually docker rm them, so we’re just going to run a random command and see the results, we don’t need to troubleshoot and keep the results, so using –rm avoids wasting space.
  • ubuntu:18.04: this refers to starting the container using the ubuntu:18.04 image as a base.
  • bash: After the image name comes the command, in this case, we want to have an interactive shell, so we use bash.

Once inside the container, we can operate under the Shell and execute any command we need. In this case, we ran cat /etc/os-release, which is a common Linux command to check the current system version, and the returned result shows that the container is an Ubuntu 18.04.1 LTS system.

List Images

To list the images that have been downloaded, you can use the docker image ls command.

$ docker image ls
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
redis                latest              5f515359c7f8        5 days ago          183 MB
nginx                latest              05a60462f8ba        5 days ago          181 MB
mongo                3.2                 fe9198c04d62        5 days ago          342 MB
<none>               <none>              00285df0df87        5 days ago          342 MB
ubuntu               18.04               329ed837d508        3 days ago          63.3MB
ubuntu               bionic              329ed837d508        3 days ago          63.3MB 

The image ID is a unique identifier for the image, and a single image can have multiple labels. So, in the example above, we can see that ubuntu:18.04 and ubuntu:bionic have the same ID because they correspond to the same image.

Mirror Volume

If you look closely, you’ll notice that the size of the image is different from the size of the image you see on Docker Hub. For example, the size of the ubuntu:18.04 image is 63.3 MB here, but in Docker Hub it is 25.47 MB. This is because the size shown in Docker Hub is the compressed size. This is because the size shown in Docker Hub is the compressed size, and the image remains compressed during download and upload, so the size shown in Docker Hub is the size of the traffic that is of more interest in network transfers. The docker image ls shows the size of the image after it has been downloaded locally and expanded, or to be more precise, the sum of the space occupied by each layer after it has been expanded, because when you look at the space after the image has been downloaded locally, you are more concerned about the size of the local disk space occupied.

Another thing to keep in mind is that the sum of the image volumes in the docker image ls list is not the actual hard disc consumption of all the images. Since Docker images are multi-tier storage structures and can be inherited and reused, different images may have a common tier because they use the same base image. Since Docker uses Union FS, you only need to keep one copy of the same tier, so the actual image hard drive footprint is likely to be much smaller than the sum of the image sizes in this list.

You can easily see how much space your images, containers, and data volumes are taking up by using the docker system df command.

$ docker system df

TYPE                TOTAL               ACTIVE              SIZE                RECLAIMABLE
Images              24                  0                   1.992GB             1.992GB (100%)
Containers          1                   0                   62.82MB             62.82MB (100%)
Local Volumes       9                   0                   652.2MB             652.2MB (100%)
Build Cache                                                 0B                  0B 

Dangling Image

In the list of mirrors above, you can also see a special mirror that has neither a repository name nor a tag, both <none>.

This image originally had a mirror name and tag, originally mongo:3.2. With the official mirror maintenance, after a new version was released when you re-do docker pull mongo:3.2, the mirror name mongo:3.2 was transferred to the newly downloaded mirror, and the name was cancelled on the old mirror, thus becoming <none>. In addition to docker pull, docker build can also cause this. Since the old image has the same name as the new one, the old image’s name is cancelled, resulting in a repository name and label of <none>. This type of unlabelled image is also known as a dangling image, and can be displayed using the following command:

$ docker image ls -f dangling=true
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
<none>              <none>              00285df0df87        5 days ago          342 MB 

Generally speaking, virtual suspension mirrors have lost their value of existence and can be deleted at will, you can use the following command to delete them.

$ docker image prune 

Middle Layer Mirror

To speed up image building and reuse resources, Docker makes use of middle-tier images. So after a while, you may see some dependent middle-tier images. The default docker image ls list only shows the top-level image, so if you want to show all images including the middle-level image, you need to add the -a argument.

docker image ls -a 

This will see a lot of unlabelled mirrors, and unlike the previous virtual suspension mirrors, many of these unlabelled mirrors are middle-tier mirrors, mirrors that other mirrors depend on. These unlabelled mirrors should not be deleted, as this will lead to errors in the upper layer mirrors due to missing dependencies. In fact, there’s no need to delete these mirrors because, as I said before, the same layer will only be stored once, and these mirrors are dependencies of other mirrors, so there isn’t an extra copy of them stored just because they’re listed, and you’ll need them anyway. Just delete the mirrors that depend on them and those dependent middle-layer mirrors will be deleted along with them.

Listing Partial Images

Without any arguments, docker image ls will list all top-level images, but sometimes we only want to list some of them. docker image ls has several arguments that can help with this.

Listing images by repository

$ docker image ls ubuntu
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              18.04               329ed837d508        3 days ago          63.3MB
ubuntu              bionic              329ed837d508        3 days ago          63.3MB 

List a specific image, i.e. specify the repository name and tag

$ docker image ls ubuntu:18.04
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              18.04               329ed837d508        3 days ago          63.3MB 

In addition to this, docker image ls supports the powerful filter parameter –filter, or simply -f. We’ve already seen the use of filters to list dummy images, but there are many more uses for them. For example, if we want to see images built after mongo:3.2, we can use the following command:

$ docker image ls -f since=mongo:3.2
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
redis               latest              5f515359c7f8        5 days ago          183 MB
nginx               latest              05a60462f8ba        5 days ago          181 MB 

If you want to see the mirrors before a certain location, you can do so by replacing since with before.

In addition, if you define a LABEL when building the image, you can filter by LABEL.

$ docker image ls -f label=com.example.version=0.1
... 

Display in a specific format

By default, docker image ls outputs a complete table, but we don’t always need it. For example, when we were deleting virtual suspension images, we needed to use docker image ls to list the IDs of all the virtual suspension images before we could give the docker image rm command as a parameter to delete the specified images, which is where the -q parameter comes in.

$ docker image ls -q
5f515359c7f8
05a60462f8ba
fe9198c04d62
00285df0df87
329ed837d508
329ed837d508 

The use of –filter with -q to produce a list of IDs in a specified range and then give it to another docker command as a parameter to do something with that set of entities in batches is very common in Docker command line usage, not just for mirrors, and we’ll be seeing this type of pairing in various commands in the future to accomplish very powerful things. So every time you see a filter in the documentation, pay more attention to how it’s used.

Other times, we may just be unhappy with the structure of a table and want to organise the columns ourselves, or we may not want to have headers so that other programs can parse the results, and so on, and this is where the Go template syntax comes in.

For example, the following command lists the mirrors directly and includes only the mirror ID and repository name:

$ docker image ls --format "{{.ID}}: {{.Repository}}"
5f515359c7f8: redis
05a60462f8ba: nginx
fe9198c04d62: mongo
00285df0df87: <none>
329ed837d508: ubuntu
329ed837d508: ubuntu 

Or intend to display it as a table equally spaced and with a header row, same as the default, but define your own columns:

$ docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
IMAGE ID            REPOSITORY          TAG
5f515359c7f8        redis               latest
05a60462f8ba        nginx               latest
fe9198c04d62        mongo               3.2
00285df0df87        <none>              <none>
329ed837d508        ubuntu              18.04
329ed837d508        ubuntu              bionic 

Delete Local Mirror

To delete a local image, you can use the docker image rm command in the format:

$ docker image rm [options] <image 1> [<image 2> ...] 

Deleting Mirror with ID, Name, and Digest

Where <mirror> can be a mirror short ID, mirror long ID, mirror name or mirror digest.

Let’s say we have some mirrors like this:

$ docker image ls
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
centos                      latest              0584b3d2cf6d        3 weeks ago         196.5 MB
redis                       alpine              501ad78535f0        3 weeks ago         21.03 MB
docker                      latest              cf693ec9b5c7        3 weeks ago         105.1 MB
nginx                       latest              e43d811ce2f4        5 weeks ago         181.5 MB 

We can delete an image using its full ID, also known as the long ID. You might use a long ID if you’re using a script, but typing it in manually is too tiresome, so more often you’ll want to use a short ID to delete an image. docker image ls lists short IDs by default, which are usually the first three characters or more, as long as they are sufficient to distinguish them from the rest of the image.

For example, if we want to delete the redis:alpine image, we can run:

$ docker image rm 501
Untagged: redis:alpine
Untagged: redis@sha256:f1ed3708f538b537eb9c2a7dd50dc90a706f7debd7e1196c9264edeea521a86d
Deleted: sha256:501ad78535f015d88872e13fa87a828425117e3d28075d0c117932b05bf189b7
Deleted: sha256:96167737e29ca8e9d74982ef2a0dda76ed7b430da55e321c071f0dbff8c2899b
Deleted: sha256:32770d1dcf835f192cafd6b9263b7b597a1778a403a109e2cc2ee866f74adf23
Deleted: sha256:127227698ad74a5846ff5153475e03439d96d4b1c7f2a449c7a826ef74a2d2fa
Deleted: sha256:1333ecc582459bac54e1437335c0816bc17634e131ea0cc48daa27d32c75eab3
Deleted: sha256:4fc455b921edf9c4aea207c51ab39b10b06540c8b4825ba57b3feed1668fa7c7 

We can also use the mirror name, which is <repository name>:<tag>, to delete the mirror.

$ docker image rm centos
Untagged: centos:latest
Untagged: centos@sha256:b2f9d1c0ff5f87a4743104d099a3d561002ac500db1b9bfa02a783a46e0d366c
Deleted: sha256:0584b3d2cf6d235ee310cf14b54667d889887b838d3f3d3033acd70fc3c48b8a
Deleted: sha256:97ca462ad9eeae25941546209454496e1d66749d53dfa2ee32bf1faabd239d38 

Of course, it would be more accurate to delete the image using the image digest.

$ docker image ls --digests
REPOSITORY                  TAG                 DIGEST                                                                    IMAGE ID            CREATED             SIZE
node                        slim                sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228   6e0c4c8e3913        3 weeks ago         214 MB

$ docker image rm node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228
Untagged: node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228 

Untagged and Deleted

If you look at the output of the above commands, you will notice that the deletion behaviour is divided into two categories, Untagged and Deleted, as we have seen before, images are uniquely identified by their IDs and summaries, and an image can have multiple tags.

So when we use the above command to delete a mirror, we are actually asking to delete a mirror with a certain tag. So the first thing we need to do is to untag all the mirrors that meet our requirements, which is what we see as Untagged information. Since an image can have multiple tags, it’s possible that after we remove the specified tag, there may be other tags pointing to the image, and if that’s the case, the Delete behaviour won’t happen. So not all docker image rm will result in deletion of the image, but may simply remove a tag.

When all the tags of the image are removed, the image will probably lose its purpose of existence, and thus the Delete behaviour will be triggered. Mirrors have a multi-tier storage structure, so when deleting they are also deleted in a sequential judgement from the top tier towards the base tier. The multi-tier structure of mirrors makes it very easy to reuse mirrors, so it is very likely that some other mirror is relying on one of the current mirror’s tiers. In this case, the deletion of the layer is still not triggered. It’s not until there are no more layers dependent on the current layer that the current layer is actually deleted. That’s why it’s sometimes strange to see that there is no other tag pointing to the image, but it’s still there, and why you may find that the number of layers removed is not the same as the number of layers you see in your docker pull.

In addition to image dependencies, you should also be aware of container dependencies on images. If there is a container started with the image (even if the container is not running), then the image cannot be deleted. As I said before, containers run on a multi-tier storage structure based on the image and a container storage layer. Therefore, if the image is relied upon by the container, then deleting it will inevitably result in a failure. If these containers are not needed, you should remove them first, and then remove the image.

Use the docker image ls command in conjunction

Like any other command that can take on multiple entities, you can use docker image ls -q in conjunction with docker image rm to delete images in batches. There are a number of ways to filter the image list that we covered in the “Image List” section that you can use.

For example, let’s say we want to remove all images from a repository named redis:

$ docker image rm $(docker image ls -q redis) 

Or delete all mirrors before mongo:3.2:

$ docker image rm $(docker image ls -q -f before=mongo:3.2) 

Using your imagination and the power of the Linux command line, you can do a lot of really awesome things.

Categories: Docker

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

Catalogue