Red Green Repeat Adventures of a Spec Driven Junkie

How to Work with Docker Images

This post feels like a step back from my previous post on managing services on Docker Swarm. The major reason for this: when working with a multi-node Docker Swarm cluster, Docker images must be on each cluster. I used two ways to get images onto the cluster: traditional file transfer and via Docker Hub.

I had to learn how to work with Docker images by:

  • Build images
  • Tag images
  • Save built images to disk
  • Load images from disk
  • Push images
  • Pull images

Docker
Icon

Requirements

If you would like to follow along this article, these are the requirements:

To build a Docker image, have a working Dockerfile. I will be using the rails-git-version app built previously that has this basic Dockerfile:

FROM ruby:2.5.0-slim

RUN apt-get update && apt-get install -qq -y --no-install-recommends \
    build-essential \
    libsqlite3-dev \
    nodejs \
    sqlite3 \
 && rm -rf /var/lib/apt/lists/*

RUN mkdir /app
WORKDIR /app

COPY Gemfile Gemfile.lock ./
RUN bundle install

COPY . .

CMD ["bundle", "exec", "rails", "s", "-p", "3000", "-b", "0.0.0.0"]

Docker Build

The Docker build command is simply: docker build ., which builds an image using Dockerfile.

vagrant@manager:/vagrant$ sudo docker build .
Sending build context to Docker daemon  446.5kB
Step 1/8 : FROM ruby:2.5.0-slim
 ---> f7d41825e9a8
Step 2/8 : RUN apt-get update && apt-get install -qq -y --no-install-recommends     build-essential     libsqlite3-dev     nodejs     sqlite3  && rm -rf /var/lib/apt/lists/*
...
Removing intermediate container f2fe6b9bc274
 ---> 182196cb787b
Successfully built 182196cb787b
vagrant@manager:/vagrant$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
<none>              <none>              182196cb787b        About an hour ago   524MB

The image built, but the name is <none> and tagged as <none>. The only way to use this is image is to use its image ID: 182196cb787b, not useful when working with Docker Swarm, which requires images have names.

documentation

Tagging Images

To tag an image, use the associated image ID in the command format:

docker tag <image ID> <name>:<tag>

vagrant@manager:/vagrant$ sudo docker tag 182196cb787b test
vagrant@manager:/vagrant$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                latest              182196cb787b        About an hour ago   524MB

The default tag is latest, here is how to specify another:

vagrant@manager:/vagrant$ sudo docker tag 182196cb787b test:v.2.10.0
vagrant@manager:/vagrant$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                latest              182196cb787b        About an hour ago   524MB
test                v.2.10.0            182196cb787b        About an hour ago   524MB

documentation

Save Image to Disk

After creating a Docker image, to save the image to disk, so you can put it on an external drive, email it, FTP it, SCP it, etc. use the Docker save command, which has the format:

docker save -o <image filename> <image>

vagrant@manager:/vagrant$ sudo docker save -o test.docker_image test
vagrant@manager:/vagrant$ ll
total 529760
drwxr-xr-x  1 vagrant vagrant       238 Sep  6  2018 ./
drwxr-xr-x 24 root    root         4096 Sep  5 22:49 ../
drwxr-xr-x  1 vagrant vagrant       442 Sep  5 22:17 .git/
-rw-r--r--  1 vagrant vagrant       536 Sep  5 22:17 .gitignore
-rw-------  1 vagrant vagrant 542459392 Sep  6  2018 test.docker_image
drwxr-xr-x  1 vagrant vagrant       102 Aug 24 22:25 .vagrant/
-rw-r--r--  1 vagrant vagrant      1427 Sep  1 01:17 Vagrantfile

This is the easiest way to make Docker images accessible.

documentation

Load Image from Disk

Now that you have a Docker image on disk, how to load a Docker image from disk so Docker services, such as docker run, or docker service create can use it? Use the docker load command, which has the command format of:

docker load < <image filename>

Let’s delete the current image from Docker and load it back:

vagrant@manager:/vagrant$ sudo docker rmi test
Untagged: test:latest
Deleted: sha256:182196cb787b222672fad14609077fb24e05803cfdc9317ea4303eb6a4e1248b
Deleted: sha256:1ddecb272c0103264ad84b115541f3946a1ea7ceff0c6524f35b176748c3249a
Deleted: sha256:28e2a7e3ce6a31fe0eb7ff2dd6cfdfa458115963b827454a2b3a2b0175f7cfee
vagrant@manager:/vagrant$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
vagrant@manager:/vagrant$ sudo docker load < test.docker_image
be46842105ce: Loading layer [==================================================>]  112.4MB/112.4MB
15e0fab9d6f7: Loading layer [==================================================>]    447kB/447kB
Loaded image: test:latest
vagrant@manager:/vagrant$ sudo docker images test
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                latest              182196cb787b        About an hour ago   524MB

documentation

Push to Docker Hub

Another way to load the Docker image: put it on Docker Hub! It’s a Docker image registry. Once an image is on there, any system that can connect to Docker Hub can load the image.

Login

After creating an account on Docker Hub, login on the command line using docker login command:

vagrant@manager:/vagrant$ sudo docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: andrewrgr
Password:
WARNING! Your password will be stored unencrypted in /home/vagrant/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

Rename Image

To push the image to Docker Hub, rename the image to the format: <docker hub username>/<image name>

The reason for this: the default registry for the docker push command is: https://docker.io (which is equivalent to Docker Hub). Adding that in front of the image, the full URI would become:

https://docker.io/docker_hub_username/image_name

For example:

vagrant@manager:/vagrant$ sudo docker images test
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                latest              182196cb787b        9 hours ago         524MB
vagrant@manager:/vagrant$ sudo docker tag 182196cb787b andrewrgr/test

This will make the full URI to be: https://docker.io/andrewrgr/test, which makes this image accessible.

Docker Push

Now that the image is ready, let’s push it up to Docker Hub!

vagrant@manager:/vagrant$ sudo docker push andrewrgr/test
The push refers to repository [docker.io/andrewrgr/test]
15e0fab9d6f7: Pushing [>                                                  ]   2.56kB/164.7kB
be46842105ce: Pushing [=>                                                 ]  2.777MB/107.8MB
074f81d79383: Pushing [==================================================>]  9.728kB
46823c0a1fdd: Pushing  1.536kB
d25206577e0d: Pushing [>                                                  ]  528.3kB/238.7MB
ec5946222cf1: Waiting
064a7e7c616b: Waiting
7825b4ce4afe: Waiting
c4376fdf62a5: Waiting
e1df5dc88d2c: Waiting
...

documentation

Docker Pull

Now the image can be pull down like any other Docker image:

vagrant@manager:/vagrant$ sudo docker pull andrewrgr/test
Using default tag: latest
latest: Pulling from andrewrgr/test
Digest: sha256:e583f595f6d99983c33ff2070a6b0767618872a49b2906cd6d43f90e56a4f04e
Status: Image is up to date for andrewrgr/test:latest

documentation

Conclusion

This time we went over how to work with Docker images through tags, at a file level: saving images to disk, loading images from disk, and using Docker Hub as a way to store and access images remotely.