Red Green Repeat Adventures of a Spec Driven Junkie

Using Docker Images

I discussed essential commands in my docker essentials article, I will apply the essential commands to work with the nginx docker image.

Just knowing commands help introduce the concept, but using them puts the concept and application together.

I have written everything below in a manner so one can follow along.

Getting Started

Get docker installed on your system to get started, instructions. The version I am using at the time of this writing is:

$ docker -v
Docker version 17.09.0-ce, build afdb6d4

Getting a Docker Image

I will work with the nginx docker image, hosted on docker hub here.

docker hub nginx
page

With docker installed, one does not need to open the web page to download the image separately. Just use docker’s commands to get the image: docker pull <image_name>

The nginx image size is 108M.

$ docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
e7bb522d92ff: Pull complete
6edc05228666: Pull complete
cd866a17e81f: Pull complete
Digest: sha256:285b49d42c703fdf257d1e2422765c4ba9d3e37768d6ea83d7fe2043dad6e63d
Status: Downloaded newer image for nginx:latest

Docker manages image files, there is no need to touch the file in the computer’s file system.

Listing Docker Images

With the image downloaded, how does one know it exists at all? Using the docker images command to list images on the system. After pulling the nginx image, one would probably see this list of docker images on their system:

$ docker images
REPOSITORY                               TAG                 IMAGE ID            CREATED             SIZE
nginx                                    latest              3f8a4339aadd        4 weeks ago         108MB

Images on Disk

If you really want to find out where docker pull put the image files, they are probably in a location depending on the operating system:

  • macOS: ~/.docker/machine/machines/default/disk.vmdk source

  • other OS: /var/lib/docker/ source

Just in case you’re really curious. :-)

Running Image in a Container

Now that the image is present on the system, let’s use it!

To run a docker image, use the docker command: docker run <image_id>:

$ docker run nginx

Hmmm.. the prompt just stopped, what’s going on?

In another terminal window, run the: docker ps command, to list active docker processes:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
2df0bba15bc6        nginx               "nginx -g 'daemon ..."   47 seconds ago      Up 46 seconds       80/tcp              sharp_boyd

So, the container is running, let’s see if the web server is accessible by going to: http://localhost.

localhost no
connection

Oh, it looks like the nginx image is running… when I look at the PORTS column, it only lists: 80/tcp, so that means the container has port 80 open, but it is not connected to any other port. Let’s connect this port to the host system by exposing it. We need to stop the container and restart it with different options.

Stopping Container

To stop the container running previously, use the: docker stop <container_id> command. For the container running, the command would be:

$ docker stop 2df0

In this case, the container_id can be either:

  • 2df0 from: CONTAINER ID
  • sharp_boyd from: NAMES

Both of these details are in the output of the docker ps command.

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
2df0bba15bc6        nginx               "nginx -g 'daemon ..."   47 seconds ago      Up 46 seconds       80/tcp              sharp_boyd

Exposing Container Ports

Let’s restart the nginx image in a container exposing port 80 to the guest system using the ports option in the docker run command:

$ docker run -p 80:80

Let’s run docker ps to see the container running:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
00b7da958ed3        nginx               "nginx -g 'daemon ..."   6 seconds ago       Up 5 seconds        0.0.0.0:80->80/tcp   sad_saha

Perfect, let’s open a web browser to: http://localhost.

Connecting a Web Browser

In a web browser, with everything working, the default nginx message would appear:

localhost connection default
content

So things are working between the container and our web browser.

nginx Output

On the terminal that started the docker container for nginx, there is some output:

$ docker run -p 80:80 nginx
172.17.0.1 - - [24/Jan/2018:13:45:22 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8" "-"

Now that we can connect the web brower to the container, let’s change the content the nginx server is delivering.

Serving Different Content

To serve different content, we have to mount the container with an option to share the folder into the folder nginx expects the files.

Let’s start by creating a new index.html file:

$ echo "hello world" > index.html

And start the container with the mount option:

docker run --mount type={bind | volume |tmpfs},source=<host directory>,target=<guest directory> <image_id>
$ docker run -p 80:80 --mount type=bind,source="$(pwd)",target=/usr/share/nginx/html nginx
172.17.0.1 - - [24/Jan/2018:23:31:01 +0000] "GET / HTTP/1.1" 200 12 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8" "-"

Let’s open the web browser to the same address again: http://localhost.

Now the web page has content:

localhost connection custom
content

Logging In

The last command covered in the Docker Essentials article is logging in to the container. I have found this useful when I want to figure out the configuration of the system.

Let’s first run the image, then find the container_id to run the docker command: docker exec -it <container_id> <shell>

The commands:

$ docker run nginx

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
d7a6faacc1da        nginx               "nginx -g 'daemon ..."   7 seconds ago       Up 6 seconds        80/tcp              condescending_goodall

$ docker exec -it d7a6 bash
root@d7a6faacc1da:/#

At this point, the whole system is accessible, so one can access any file, even the nginx configuration file, nginx.conf:

root@6f7577b19281:/# cat /etc/nginx/nginx.conf

user  nginx;
worker_processes  1;

error_log /dev/stdout info;
daemon off;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /dev/stdout;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

I have found this useful when images do not have documentation on the images.

Conclusion

I have learned the nuances of Docker better by applying essential commands to a running image, like nginx. I hope you did as well, getting a better feel for how images, containers, ports, mounts, and logging in work.