Introduction

Without images there is no reason of running Docker. Images are integral part of infrastructure like virtual machines on hypervisor environment. In this article we are covering basic container operations (search, pull, push, list,) public and private registries and tagging operation. Docker by default is accessing official Docker Hub site (hub.docker.com). But you can always switch access to other public or your private registry. It is very important to know how to search, pull, push and tag container images. So let’s see how it works.

Public registries

Public registries are easiest and most straightforward way to access and download images. You have to consider if your environment includes production services because public images are not known by its secure nature. Everybody with account can push and publish images. Reports say that 70% of images on Docker Hub are not secure. Our recommendation is to be careful with public images and use them in test environment only. One of the trusted sources for public images is Red Hat image repository. Check the Docker security for more details.

Basic image operations

Search

To search for particular image you can use Docker search command:

[root@swmanager Docker]# Docker search mysql

NAME DESCRIPTION STARS OFFICIAL

mysql MySQL is a widely used, open-source relation… 9609 [OK]

mariadb is a community-developed fork of MyS… 3493 [OK]

mysql/mysql-server Optimized MySQL Server Docker images. Create… 702 [OK]

centos/mysql-57-centos7 MySQL 5.7 SQL database server 76

mysql/mysql-cluster Experimental MySQL Cluster Docker images. Cr… 69

centurylink/mysql Image containing mysql. Optimized to be link… 61 [OK]

deitch/mysql-backup REPLACED! Please use http://hub.docker.com/r… 41 [OK]

There are few handy switches you can use to filter the search:

–filter=is-automated (images built with Dockerfile)

–stars=N (number of stars, i.e. image ratings by user experience)

Let’s check for automated builds with stars more than 500:

[root@swmanager Docker]# Docker search mysql –filter=is-automated=true –filter=stars=500

NAME DESCRIPTION STARS OFFICIAL

mysql/mysql-server Optimized MySQL Server Docker images. Create… 702 [OK]

Pull command

Use the pull command to retrieve images from the defined registry. Leave the default configuration Docker automatically pulls images from Docker Hub.

[root@swmanager Docker]# Docker pull mysql

Using default tag: latest

latest: Pulling from library/mysql

8559a31e96f4: Pull complete

d51ce1c2e575: Pull complete

…..

Pull images with all tags included:

[root@swmanager /]# Docker pull Redis –all-tags=true

2-32bit: Pulling from library/Redis

51f5c6a04d83: Pull complete

…..

2.6-32bit: Pulling from library/Redis

d4bce7fd68df: Download complete

….

2.6.17-32bit: Pulling from library/Redis

….

2.8-32bit: Pulling from library/Redis

….

Docker images are stored locally on same system where Docker is installed. To check local images use Docker images command:

[root@swmanager /]# Docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

nginx <none> 602e111c06b6 6 weeks ago 127MB

ubuntu latest 72300a873c2c 3 months ago 64.2MB

centos latest 470671670cac 4 months ago 237MB

hello-world latest fce289e99eb9 17 months ago 1.84kB

Redis 2-32bit 19865a7ae96c 4 years ago 203MB

Redis 2.8-32bit 19865a7ae96c 4 years ago 203MB

Redis 2.6-32bit 62b0a5c3ea45 4 years ago 158MB

Redis 2.6.17-32bit 62b0a5c3ea45 4 years ago 158MB

Redis 2.6 a081f7d44c38 4 years ago 150MB

Redis 2.6.17 a081f7d44c38 4 years ago 150MB

Redis 2.8.18 5f9a9a936de2 5 years ago 111MB

Redis 2.8.17 01aaba7226f1 5 years ago 111MB

Redis 2.8.16 8b6103fd7b3e 5 years ago 111MB

Redis 2.8.15 dbb560009c50 5 years ago 111MB

Redis 2.8.14 4aad650df84a 5 years ago 111MB

Redis 2.8.13 c4f8a05f3aff 5 years ago 111MB

Redis 2.8.12 98bc726ecd17 5 years ago 111MB

Redis 2.8.11 2fb854cb3f76 5 years ago 111MB

Redis 2.8.10 33fe9dbeb30c 5 years ago 111MB

You can see various image version of Redis which was used by command before.

Docker tag image

Command is used to distinguish the image versions like any other software. If no tag is defined then the latest version of image is used. For example let’s pull the mysql version 5.5:

[root@swmanager ~]# Docker pull mysql:5.5

5.5: Pulling from library/mysql

743f2d6c1f65: Downloading [======================> ] 10.34MB/22.49MB

3f0c413ee255: Download complete

aef1ef8f1aac: Download complete

f9ee573e34cb: Download complete

3f237e01f153: Download complete

….

Saving and loading images

Images can be saved in two ways: save command or push to public/private registry.

Saving images is easy and done in classic tar format:

[root@swmanager ~]# Docker save -o mysql.tar mysql

Notice the o parameter, if not used save will go to standard output. We defined name mysql.tar and local image mysql.

Tar format can be compressed with gzip to save more space:

[root@swmanager ~]# Docker save -o mysql.tar mysql | gzip > mysql.tar.gz

[root@swmanager ~]# ls -la | grep mysql

-rw——- 1 root root 2688 Mar 31 08:51 .mysql_history

-rw——- 1 root root 209714176 Jun 12 23:06 mysql.tar

-rw-r–r– 1 root root 20 Jun 12 23:06 mysql.tar.gz

Image in tar or gzip format can be transferred anywhere where Docker is installed and loaded with load option:

[root@swmanager ~]# Docker load -i mysql.tar

Loaded image: mysql:5.5

Push to public registry

Other way to save image is to push image to public or private registry. In this example we will cover public registry Docker Hub.

If you have account on Docker Hub first step is authentication:

[root@swmanager ~]# Docker login –username=username –password=password

WARNING! Using –password via the CLI is insecure. Use –password-stdin.

WARNING! Your password will be stored unencrypted in /root/.Docker/config.json.

Configure a credential helper to remove this warning. See

https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

Check local image cache:

[root@swmanager ~]# Docker images

[root@swmanager ~]# Docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

nginx <none> 602e111c06b6 7 weeks ago 127MB

ubuntu latest 72300a873c2c 3 months ago 64.2MB

centos latest 470671670cac 4 months ago 237MB

mysql 5.5 d404d78aa797 13 months ago 205MB

hello-world latest fce289e99eb9 17 months ago 1.84kB

Tag image with your username:

[root@swmanager ~]# Docker tag d404d78aa797 username/mysql

Push image:

[root@swmanager ~]# Docker push username/mysql

Docker delete image

To keep your local image cache simple and clean you have to delete old and unused image. Each time image is pulled from registry it is stored on your local system. Before image deletion, make sure that there is no container which is running and using particular image. Container should be off to successfully delete image. If image is referenced use the –force=true parameter.

Let’s delete local mysql images with Docker delete image. First write mysql image id.

[root@swmanager ~]# Docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

nginx <none> 602e111c06b6 7 weeks ago 127MB

ubuntu latest 72300a873c2c 3 months ago 64.2MB

centos latest 470671670cac 4 months ago 237MB

mysql 5.5 d404d78aa797 13 months ago 205MB

Use Docker delete command:

[root@swmanager ~]# Docker rmi d404d78aa797

Error response from daemon: conflict: unable to delete d404d78aa797 (must be forced) – image is referenced in multiple repositories

Unfortunately we must use –force=true because image is referenced:

[root@swmanager ~]# Docker rmi d404d78aa797 –force=true

Untagged username/mysql:latest

Untagged: jadranmestrovic/mysql@sha256:c9c671d0c959183154313d6830d46f9a00d5937f97415c15ebd3c6844f6f1467

Untagged: mysql:5.5

Untagged: mysql@sha256:12da85ab88aedfdf39455872fb044f607c32fdc233cd59f1d26769fbf439b045

There is handy command to delete all unused images:

Docker rmi $(Docker images -q)

[root@swmanager ~]# Docker rmi $(Docker images -q)

Modifying images

When Docker images are up and running you can save image current state to the new image with command Docker commit. However, this is not recommended approach because you will saturate new image with log, process ID files and it will not be a clean way to build new image. Recommended way is always to use Docker file. But let check example with Docker commit.

Check running containers:

[root@swmanager ~]# Docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

5a01497cce2d nginx:latest “nginx -g ‘daemon of…” 3 minutes ago Up 2 minutes 80/tcp nginx.1.n1zzqfn5qa3iigbod9cbipfoa

bb024f708fa2 nginx:latest “nginx -g ‘daemon of…” 3 minutes ago Up 2 minutes 80/tcp nginx.2.x7hnb7kv8cq9sdb2bfqi2ywd9

Run diff command to check differences between original and current nginx image:

[root@swmanager ~]# Docker diff nginx.1.n1zzqfn5qa3iigbod9cbipfoa

C /run

A /run/nginx.pid

C /var

C /var/cache

C /var/cache/nginx

A /var/cache/nginx/proxy_temp

A /var/cache/nginx/scgi_temp

A /var/cache/nginx/uwsgi_temp

A /var/cache/nginx/client_temp

A /var/cache/nginx/fastcgi_temp

Changed file is tagged with C label while new file is tagged with A label.

Commit current running image to new image:

[root@swmanager ~]# Docker commit nginx.1.n1zzqfn5qa3iigbod9cbipfoa nginx3

sha256:b778cd9e1fff6ecf36b8359768fc91bfacb71b4cba986398e425f86b3a3201b6

Check new image:

[root@swmanager ~]# Docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

nginx3 latest b778cd9e1fff About a minute ago 127MB

Docker tag image

Docker tag image is used to tag images based on the same software in order to distinguish software versions. If tag is not provided, the latest software release is used. The latest software release does not necessarily mean the latest build.

Tag the local Ubuntu image:

[root@swmanager ~]# Docker tag ubuntu devel/ubuntu:1.1

Remove the tag:

[root@swmanager ~]# docker rmi devel/ubuntu:1.1

Untagged: devel/ubuntu:1.1

Docker local registry

It is time to setup you own local registry and procedure is pretty simple because there is already image which provides local registry services. In the following example we will set up the local registry, pull the image from public registry, tag it with our own local tag and push it to the local registry. In order to test the local registry, all Ubuntu images will be removed and pulled from local registry. Private registry can be a good choice if you want your own independent and secure registry. It is a pretty easy procedure that involves installing the pre-built container-registry. The hardest part of the installation is securing the registry from remote access. Let’s see how to do it:

  1. Pull the registry container
  2. Install the registry container
  3. Securing the private registry

Just run the container with registry image:

[root@swmanager ~]# Docker run -p 5000:5000 -dit –restart=always –name registry registry:2

fc97bb77df4c5316b645682e82ec9f32343e4fc12f41ecb75c00afca54d4a5d9

New container with private registry image is started on port 5000. Parameter restart=always is used to container to start each time Docker starts.

Pull the Ubuntu image from public registry:

[root@swmanager ~]# Docker pull ubuntu

Using default tag: latest

latest: Pulling from library/ubuntu

….

To use local registry it is very important to tag the local image with following format:

registryserver:portnumber/image name:tag

Otherwise Docker will operate with default option and that is public registry.

Tag the Ubuntu image with local tag:

[root@swmanager ~]# Docker tag ubuntu swmanager.local:5000/mylocalubuntu:16.1

Check that image is in the list:

[root@swmanager ~]# Docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

swmanager.local:5000/mylocalubuntu 16.1 adafef2e596e 6 days ago 73.9MB

Push the Ubuntu image to your local registry:

[root@swmanager ~]# Docker push swmanager.local:5000/mylocalubuntu

The push refers to repository [swmanager.local:5000/mylocalubuntu]

8891751e0a17: Pushed

2a19bd70fcd4: Pushed

9e53fd489559: Pushed

7789f1a3d4e9: Pushed

latest: digest: sha256:5747316366b8cc9e3021cd7286f42b2d6d81e3d743e2ab571f55bcd5df788cc8 size: 1152

Remove Ubuntu from public registry and local ubuntu image:

[root@swmanager ~]# Docker image remove ubuntu

Untagged: ubuntu:latest

Untagged: ubuntu@sha256:747d2dbbaaee995098c9792d99bd333c6783ce56150d1b11e333bbceed5c54d7

[root@swmanager ~]# Docker image remove localhost:5000/mylocalubuntu

Untagged: localhost:5000/mylocalubuntu:latest

Untagged: localhost:5000/mylocalubuntu@sha256:5747316366b8cc9e3021cd7286f42b2d6d81e3d743e2ab571f55bcd5df788cc8

Deleted: sha256:1d622ef86b138c7e96d4f797bf5e4baca3249f030c575b9337638594f2b63f01

Deleted: sha256:279e836b58d9996b5715e82a97b024563f2b175e86a53176846684f0717661c3

Deleted: sha256:39865913f677c50ea236b68d81560d8fefe491661ce6e668fd331b4b680b1d47

Deleted: sha256:cac81188485e011e56459f1d9fc9936625a1b62cacdb4fcd3526e5f32e280387

Deleted: sha256:7789f1a3d4e9258fbe5469a8d657deb6aba168d86967063e9b80ac3e1154333f

Pull image from your local registry:

[root@swmanager ~]# Docker pull swmanager.local:5000/mylocalubuntu

Using default tag: latest

latest: Pulling from mylocalubuntu

d51af753c3d3: Pull complete

fc878cd0a91c: Pull complete

6154df8ff988: Pull complete

fee5db0ff82f: Pull complete

Digest: sha256:5747316366b8cc9e3021cd7286f42b2d6d81e3d743e2ab571f55bcd5df788cc8

Status: Downloaded newer image for localhost:5000/mylocalubuntu:latest

localhost:5000/mylocalubuntu:latest

Choosing the right storage location

By default registry images are stored on predefined Docker volume stored in following path: var/lib/Docker. But what if you want to store your private image data on external source? Then only option is to use bind mount. Example mounts host path /mnt/external to Docker registry /var/lib/registry.

Docker run -d -p 5000:5000 –restart=always –name registry -v /mnt/registry:/var/lib/registry registry:2

Note:

Using the storage drivers private registry can be stored in any cloud like Google, AWS or IBM.

Setting the secure private registry for remote access

By default Docker use secure TLS connection. We will demonstrate the configuration of secure connection with self-signed certificate:

Create directory for self-signed certificate:

[root@swmanager ~]# mkdir -p /Docker/certs

Start private registry with configured certificate and key:

[root@swmanager certs]# Docker run -d -p 5000:5000 –restart=always –name registry -v /Docker/certs:/Docker/certs -e REGISTRY_HTTP_TLS_CERTIFICATE=/Docker/certs/docker.crt -e REGISTRY_HTTP_TLS_KEY=/Docker/certs/Docker. Key registry

Generate the self-signed certificate with open SSL command:

[root@swmanager ~]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout /docker/certs/docker.ca -x509 -days 365 -out /Docker/certs/docker.key

Generating a RSA private key

…………………………++++

…………………………………………………………………………………………………..++++

writing new private key to ‘/Docker/certs/docker.ca’

—–

You are about to be asked to enter information that will be incorporated

into your certificate request.

What you are about to enter is what is called a Distinguished Name or a DN.

There are quite a few fields but you can leave some blank

For some fields there will be a default value,

If you enter ‘.’, the field will be left blank.

—–

Country Name (2 letter code) [XX]:GB

State or Province Name (full name) []:GB

Locality Name (eg, city) [Default City]:GB

Organization Name (eg, company) [Default Company Ltd]:localhost

Organizational Unit Name (eg, section) []:IT

Common Name (eg, your name or your server’s hostname) []:swmanager.local

Email Address []:swmanager@local

Copy the certificate from server to client:

[root@swworker1 ~]# scp -pr root@swmanager.local:/docker/certs/docker.ca /etc/Docker/certs.d/swmanager.local:5000/

The authenticity of host ‘swmanager.local (192.168.78.3)’ can’t be established.

ECDSA key fingerprint is SHA256:iNe0xpuyJDPtmCQIp+jg5oR18BcvidZRpuX8qltm1tg.

Are you sure you want to continue connecting (yes/no/[fingerprint])? yes

Warning: Permanently added ‘swmanager.local,192.168.78.3’ (ECDSA) to the list of known hosts.

root@swmanager.local’s password:

/etc/dokcer/certs.d/swmanager.local:5000/: Not a directory

Restart Docker service:

[root@swworker1 ~]# systemctl restart Docker

Push the previosuly tagged Redis image to your private registry:

[root@swworker1 swmanager.local:5000]# Docker push swmanager.local:5000/Redis:v1

The push refers to repository [swmanager.local:5000/Redis]

7b9c5be81844: Pushed

67c707dbd847: Pushed

72d3a7e6fe02: Pushed

cdaf0fb0082b: Pushed

e6b49c7dcaac: Pushed

13cb14c2acd3: Pushed

v1: digest: sha256:76ff608805ca40008d6e0f08180d634732d8bf4728b85c18ab9bdbfa0911408d size: 1572

Check image on private registry server:

[root@swmanager certs]# Docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

ubuntu latest adafef2e596e 8 days ago 73.9MB

swmanager.local:5000/mylocalubuntu 16.1 adafef2e596e 8 days ago 73.9MB

registry latest 2d4f4b5309b1 3 weeks ago 26.2MB

nginx3 latest b778cd9e1fff 4 weeks ago 127MB

Redis latest 235592615444 5 weeks ago 104MB

swmanager.local:5000/Redis v1 235592615444 5 weeks ago 104MB

Let’s test the image pull from private registry. First delete local copy of Redis image:

[root@swworker1 swmanager.local:5000]# Docker image rm swmanager.local:5000/Redis:v1

Untagged: swmanager.local:5000/Redis:v1

Untagged: swmanager.local:5000/Redis@sha256:76ff608805ca40008d6e0f08180d634732d8bf4728b85c18ab9bdbfa0911408d

[root@swworker1 swmanager.local:5000]#

And pull the Redis image from private registry:

[root@swworker1 swmanager.local:5000]# Docker pull swmanager.local:5000/Redis:v1

v1: Pulling from Redis

Digest: sha256:76ff608805ca40008d6e0f08180d634732d8bf4728b85c18ab9bdbfa0911408d

Status: Downloaded newer image for swmanager.local:5000/Redis:v1

swmanager.local:5000/Redis:v1

Check that image is now on local server:

[root@swworker1 swmanager.local:5000]# Docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

Redis latest 235592615444 5 weeks ago 104MB

swmanager.local:5000/Redis v1 235592615444 5 weeks ago 104MB

[root@swworker1 ~]# systemctl restart Docker