Running your own project

By now, we are considerably familiar with the basic Docker commands. Let's up the ante. For the next couple of commands, I am going to use one of my side projects. Feel free to use a project of your own.

Let's start by listing out our requirements to determine the arguments we must pass to the docker run command.

Our application is going to run on Node.js, so we will choose the well-maintained dockerfile/nodejs image to start our base container:

  • We know that our application is going to bind to port 8000, so we will expose the port to 8000 of the host.
  • We need to give a descriptive name to the container so that we can reference it in future commands. In this case, let's choose the name of the application:
    $ docker run -it --name code.it dockerfile/nodejs /bin/bash
    [ root@3b0d5a04cdcd:/data ]$ cd /home
    [ root@3b0d5a04cdcd:/home ]$
    

Once you have started your container, you need to check whether the dependencies for your application are already available. In our case, we only need Git (apart from Node.js), which is already installed in the dockerfile/nodejs image.

Now that our container is ready to run our application, all that is remaining is for us to fetch the source code and do the necessary setup to run the application:

$ git clone https://github.com/shrikrishnaholla/code.it.git
$ cd code.it && git submodule update --init --recursive

This downloads the source code for a plugin used in the application.

Then run the following command:

$ npm install

Now all the node modules required to run the application are installed.

Next, run this command:

$ node app.js

Now you can go to localhost:8000 to use the application.

The diff command

The diff command shows the difference between the container and the image it is based on. In this example, we are running a container with code.it. In a separate tab, run this command:

$ docker diff code.it
C /home
A /home/code.it
...

The commit command

The commit command creates a new image with the filesystem of the container. Just as with Git's commit command, you can set a commit message that describes the image:

$ docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

Flag

Explanation

-p, --pause

This pause the container during commit (availabe from v1.1.1+ onwards).

-m, --message=""

This is a commit message. It can be a description of what the image does.

-a, --author=""

This displays the author details.

For example, let's use this command to commit the container we have set up:

$ docker commit -m "Code.it – A browser based text editor and interpreter" -a "Shrikrishna Holla <s**[email protected]>" code.it shrikrishna/code.it:v1

Tip

Replace the author details and the username portion of the image name in this example if you are copying these examples.

The output will be a lengthy image ID. If you look at the command closely, we have named the image shrikrishna/code.it:v1. This is a convention. The first part of an image/repository's name (before the forward slash) is the Docker Hub username of the author. The second part is the intended application or image name. The third part is a tag (usually a version description) separated from the second part by a colon.

Note

Docker Hub is a public registry maintained by Docker, Inc. It hosts public Docker images and provides services to help you build and manage your Docker environment. More details about it can be found at https://hub.docker.com.

A collection of images tagged with different versions is a repository. The image you create by running the docker commit command will be a local one, which means that you will be able to run containers from it but it won't be available publicly. To make it public or to push to your private Docker registry, use the docker push command.

The images command

The images command lists all the images in the system:

$ docker images [OPTIONS] [NAME]

Flag

Explanation

-a, --all

This shows all images, including intermediate layers.

-f, --filter=[]

This provides filter values.

--no-trunc

This doesn't truncate output (shows complete ID).

-q, --quiet

This shows only the image IDs.

Now let's look at a few examples of the usage of the image command:

$ docker images
REPOSITORY           TAG   IMAGE ID       CREATED    VIRTUAL SIZE
shrikrishna/code.it  v1    a7cb6737a2f6   6m ago     704.4 MB

This lists all top-level images, their repository and tags, and their virtual size.

Docker images are nothing but a stack of read-only filesystem layers. A union filesystem, such as AUFS, then merges these layers and they appear to be one filesystem.

In Docker-speak, a read-only layer is an image. It never changes. When running a container, the processes think that the entire filesystem is read-write. But the changes go only at the topmost writeable layer, which is created when a container is started. The read-only layers of the image remain unchanged. When you commit a container, it freezes the top layer (the underlying layers are already frozen) and turns it into an image. Now, when a container is started this image, all the layers of the image (including the previously writeable layer) are read-only. All the changes are now made to a new writeable layer on top of all the underlying layers. However, because of how union filesystems (such as AUFS) work, the processes believe that the filesystem is read-write.

A rough schematic of the layers involved in our code.it example is as follows:

The images command

Note

At this point, it might be wise to think just how much effort is to be made by the union filesystems to merge all of these layers and provide a consistent performance. After some point, things inevitably break. AUFS, for instance, has a 42-layer limit. When the number of layers goes beyond this, it just doesn't allow the creation of any more layers and the build fails. Read https://github.com/docker/docker/issues/1171 for more information on this issue.

The following command lists the most recently created images:

$ docker images | head

The -f flag can be given arguments of the key=value type. It is frequently used to get the list of dangling images:

$ docker images -f "dangling=true"

This will display untagged images, that is, images that have been committed or built without a tag.

The rmi command

The rmi command removes images. Removing an image also removes all the underlying images that it depends on and were downloaded when it was pulled:

$ docker rmi [OPTION] {IMAGE(s)]

Flag

Explanation

-f, --force

This forcibly removes the image (or images).

--no-prune

This command does not delete untagged parents.

This command removes one of the images from your machine:

$ docker rmi test

The save command

The save command saves an image or repository in a tarball and this streams to the stdout file, preserving the parent layers and metadata about the image:

$ docker save -o codeit.tar code.it

The -o flag allows us to specify a file instead of streaming to the stdout file. It is used to create a backup that can then be used with the docker load command.

The load command

The load command loads an image from a tarball, restoring the filesystem layers and the metadata associated with the image:

$ docker load -i codeit.tar

The -i flag allows us to specify a file instead of trying to get a stream from the stdin file.

The export command

The export command saves the filesystem of a container as a tarball and streams to the stdout file. It flattens filesystem layers. In other words, it merges all the filesystem layers. All of the metadata of the image history is lost in this process:

$ sudo Docker export red_panda > latest.tar

Here, red_panda is the name of one of my containers.

The import command

The import command creates an empty filesystem image and imports the contents of the tarball to it. You have the option of tagging it the image:

$ docker import URL|- [REPOSITORY[:TAG]]

URLs must start with http.

$ docker import http://example.com/test.tar.gz # Sample url

If you would like to import from a local directory or archive, you can use the - parameter to take the data from the stdin file:

$ cat sample.tgz | docker import – testimage:imported

The tag command

You can add a tag command to an image. It helps identify a specific version of an image.

For example, the python image name represents python:latest, the latest version of Python available, which can change from time to time. But whenever it is updated, the older versions are tagged with the respective Python versions. So the python:2.7 command will have Python 2.7 installed. Thus, the tag command can be used to represent versions of the images, or for any other purposes that need identification of the different versions of the image:

$ docker tag IMAGE [REGISTRYHOST/][USERNAME/]NAME[:TAG]

The REGISTRYHOST command is only needed if you are using a private registry of your own. The same image can have multiple tags:

$ docker tag shrikrishna/code.it:v1 shrikrishna/code.it:latest

Tip

Whenever you are tagging an image, follow the username/repository:tag convention.

Now, running the docker images command again will show that the same image has been tagged with both the v1 and latest commands:

$ docker images
REPOSITORY            TAG     IMAGE ID      CREATED     VIRTUAL SIZE
shrikrishna/code.it   v1      a7cb6737a2f6  8 days ago  704.4 MB
shrikrishna/code.it   latest  a7cb6737a2f6  8 days ago  704.4 MB

The login command

The login command is used to register or log in to a Docker registry server. If no server is specified, https://index.docker.io/v1/ is the default:

$ Docker login [OPTIONS] [SERVER]

Flag

Explanation

-e, --email=""

Email

-p, --password=""

Password

-u, --username=""

Username

If the flags haven't been provided, the server will prompt you to provide the details. After the first login, the details will be stored in the $HOME/.dockercfg path.

The push command

The push command is used to push an image to the public image registry or a private Docker registry:

$ docker push NAME[:TAG]

The history command

The history command shows the history of the image:

$ docker history shykes/nodejs
IMAGE         CREATED        CREATED BY                      SIZE
6592508b0790  15 months ago  /bin/sh -c wget http://nodejs.  15.07 MB
0a2ff988ae20  15 months ago  /bin/sh -c apt-get install ...  25.49 MB
43c5d81f45de  15 months ago  /bin/sh -c apt-get update       96.48 MB
b750fe79269d  16 months ago  /bin/bash                       77 B
27cf78414709  16 months ago                                  175.3 MB

The events command

Once started, the events command prints all the events that are handled by the docker daemon, in real time:

$ docker events [OPTIONS]

Flag

Explanation

--since=""

This shows all events created since timestamp (in Unix).

--until=""

This stream events until timestamp.

For example the events command is used as follows:

$ docker events

Now, in a different tab, run this command:

$ docker start code.it

Then run the following command:

$ docker stop code.it

Now go back to the tab running Docker events and see the output. It will be along these lines:

[2014-07-21 21:31:50 +0530 IST] c7f2485863b2c7d0071477e6cb8c8301021ef9036afd4620702a0de08a4b3f7b: (from dockerfile/nodejs:latest) start

[2014-07-21 21:31:57 +0530 IST] c7f2485863b2c7d0071477e6cb8c8301021ef9036afd4620702a0de08a4b3f7b: (from dockerfile/nodejs:latest) stop

[2014-07-21 21:31:57 +0530 IST] c7f2485863b2c7d0071477e6cb8c8301021ef9036afd4620702a0de08a4b3f7b: (from dockerfile/nodejs:latest) die

You can use flags such as --since and --until to get the event logs of specific timeframes.

The wait command

The wait command blocks until a container stops, then prints its exit code:

$ docker wait CONTAINER(s)

The build command

The build command builds an image from the source files at a specified path:

$ Docker build [OPTIONS] PATH | URL | -

Flag

Explanation

-t, --tag=""

This is the repository name (and an optional tag) to be applied to the resulting image in case of success.

-q, --quiet

This suppresses the output, which by default is verbose.

--rm=true

This removes intermediate containers after a successful build.

--force-rm

This always removes intermediate containers, even after unsuccessful builds.

--no-cache

This command does not use the cache while building the image.

This command uses a Dockerfile and a context to build a Docker image.

A Dockerfile is like a Makefile. It contains instructions on the various configurations and commands that need to be run in order to create an image. We will look at writing Dockerfiles in the next section.

Tip

It would be a good idea to read the section about Dockerfiles first and then come back here to get a better understanding of this command and how it works.

The files at the PATH or URL paths are called context of the build. The context is used to refer to the files or folders in the Dockerfile, for instance in the ADD instruction (and that is the reason an instruction such as ADD ../file.txt won't work. It's not in the context!).

When a GitHub URL or a URL with the git:// protocol is given, the repository is used as the context. The repository and its submodules are recursively cloned in your local machine, and then uploaded to the docker daemon as the context. This allows you to have Dockerfiles in your private Git repositories, which you can access from your local user credentials or from the Virtual Private Network (VPN).

Uploading to Docker daemon

Remember that Docker engine has both the docker daemon and the Docker client. The commands that you give as a user are through the Docker client, which then talks to the docker daemon (either through a TCP or a Unix socket), which does the necessary work. The docker daemon and Docker host can be in different hosts (which is the premise with which boot2Docker works), with the DOCKER_HOST environment variable set to the location of the remote docker daemon.

When you give a context to the docker build command, all the files in the local directory get tared and are sent to the docker daemon. The PATH variable specifies where to find the files for the context of the build in the docker daemon. So when you run docker build ., all the files in the current folder get uploaded, not just the ones listed to be added in the Dockerfile.

Since this can be a bit of a problem (as some systems such as Git and some IDEs such as Eclipse create hidden folders to store metadata), Docker provides a mechanism to ignore certain files or folders by creating a file called .dockerignore in the PATH variable with the necessary exclusion patterns. For an example, look up https://github.com/docker/docker/blob/master/.dockerignore.

If a plain URL is given or if the Dockerfile is streamed through the stdin file, then no context is set. In these cases, the ADD instruction works only if it refers to a remote URL.

Now let's build the code.it example image through a Dockerfile. The instructions on how to create this Dockerfile are provided in the Dockerfile section.

At this point, you would have created a directory and placed the Dockerfile inside it. Now, on your terminal, go to that directory and execute the docker build command:

$ docker build -t shrikrishna/code.it:docker Dockerfile .
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon
Step 0 : FROM Dockerfile/nodejs
 ---> 1535da87b710
Step 1 : MAINTAINER Shrikrishna Holla <s**[email protected]>
 ---> Running in e4be61c08592
 ---> 4c0eabc44a95
Removing intermediate container e4be61c08592
Step 2 : WORKDIR /home
 ---> Running in 067e8951cb22
 ---> 81ead6b62246
Removing intermediate container 067e8951cb22
. . . . .
. . . . .
Step 7 : EXPOSE  8000
 ---> Running in 201e07ec35d3
 ---> 1db6830431cd
Removing intermediate container 201e07ec35d3
Step 8 : WORKDIR /home
 ---> Running in cd128a6f090c
 ---> ba05b89b9cc1
Removing intermediate container cd128a6f090c
Step 9 : CMD     ["/usr/bin/node", "/home/code.it/app.js"]
 ---> Running in 6da5d364e3e1
 ---> 031e9ed9352c
Removing intermediate container 6da5d364e3e1
Successfully built 031e9ed9352c

Now, you will be able to look at your newly built image in the output of Docker images

REPOSITORY          TAG        IMAGE ID     CREATED      VIRTUAL SIZE
shrikrishna/code.it Dockerfile 031e9ed9352c 21 hours ago 1.02 GB

To see the caching in action, run the same command again

$ docker build -t shrikrishna/code.it:dockerfile .
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon
Step 0 : FROM dockerfile/nodejs
 ---> 1535da87b710
Step 1 : MAINTAINER Shrikrishna Holla <s**[email protected]>
 ---> Using cache
 ---> 4c0eabc44a95
Step 2 : WORKDIR /home
 ---> Using cache
 ---> 81ead6b62246
Step 3 : RUN     git clone https://github.com/shrikrishnaholla/code.it.git
 ---> Using cache
 ---> adb4843236d4
Step 4 : WORKDIR code.it
 ---> Using cache
 ---> 755d248840bb
Step 5 : RUN     git submodule update --init --recursive
 ---> Using cache
 ---> 2204a519efd3
Step 6 : RUN     npm install
 ---> Using cache
 ---> 501e028d7945
Step 7 : EXPOSE  8000
 ---> Using cache
 ---> 1db6830431cd
Step 8 : WORKDIR /home
 ---> Using cache
 ---> ba05b89b9cc1
Step 9 : CMD     ["/usr/bin/node", "/home/code.it/app.js"]
 ---> Using cache
 ---> 031e9ed9352c
Successfully built 031e9ed9352c

Tip

Now experiment with this caching. Change one of the lines in the middle (the port number for example), or add a RUN echo "testing cache" line somewhere in the middle and see what happens.

An example of building an image using a repository URL is as follows:

$ docker build -t shrikrishna/optimus:git_url  git://github.com/shrikrishnaholla/optimus
Sending build context to Docker daemon 1.305 MB
Sending build context to Docker daemon
Step 0 : FROM        dockerfile/nodejs
 ---> 1535da87b710
Step 1 : MAINTAINER  Shrikrishna Holla
 ---> Running in d2aae3dba68c
 ---> 0e8636eac25b
Removing intermediate container d2aae3dba68c
Step 2 : RUN         git clone https://github.com/pesos/optimus.git /home/optimus
 ---> Running in 0b46e254e90a
. . . . .
. . . . .
. . . . .
Step 5 : CMD         ["/usr/local/bin/npm", "start"]
 ---> Running in 0e01c71faa0b
 ---> 0f0dd3deae65
Removing intermediate container 0e01c71faa0b
Successfully built 0f0dd3deae65
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset