Distributed Systems Practice Notes

Docker and Containers - Docker Images Lab

October 29, 2018

This lab works on 2 ways of creating a docker image, namely, from binary files of container or from Dockerfile. The advantages of using Dockerfile and how Dockerfile relates to image layers are both discussed.

Learning Outcomes

  • How to create a Docker image from a container binary
  • How to create a Docker image from a Dockerfile
  • Advantages of using Dockerfile
  • What are Docker image layers, how they relate to a Dockerfile

Operations

Image Creation from a Container

create from container

This example shows that we can create a container, add all the libraries and binaries in it and then commit it in order to create an image. This approach of manually installing software in a container and then committing it to a custom image is just one way to create an image. It works fine and is quite common.

  • Start by running an interactive shell in a ubuntu container
docker container run -ti ubuntu bash
  • Install a package called figlet in this container
apt-get update
apt-get install -y figlet
figlet "hello docker"
  • Exit container and find out its container ID
docker container ls -a
  • “Commit” this container to create an image

Commit creates an image locally on the system running the Docker engine.

docker container commit CONTAINER_ID
  • Find out image ID and tag the image
docker image ls
docker image tag <IMAGE_ID> ourfiglet
  • Run a container based on the newly created ourfiglet image
docker container run ourfiglet figlet hello

Image Creation from Dockerfile

create from dockerfile

Instead of creating a static binary image, we can use a file called a Dockerfile to create an image. The final result is essentially the same, but with a Dockerfile we are supplying the instructions for building the image, rather than just the raw binary files. This is useful because it becomes much easier to manage changes, especially as your images get bigger and more complex.

  • Create index.js file with content below
var os = require("os");
var hostname = os.hostname();
console.log("hello from " + hostname);
  • Create Dockerfile with content below
FROM alpine
RUN apk update && apk add nodejs
COPY . /app
WORKDIR /app
CMD ["node","index.js"]
  • Build image out of this Dockerfile and name it hello:v0.1
docker image build -t hello:v0.1 .
  • Start a container to check that our applications runs correctly
docker container run hello:v0.1
  • Dockerfile Explained

    • Specifies a base image to pull FROM - the alpine image we used in earlier labs.
    • Then it RUNs two commands (apk update and apk add) inside that container which installs the Node.js server.
    • Then we told it to COPY files from our working directory in to the container. The only file we have right now is our index.js.
    • Next we specify the WORKDIR - the directory the container should use when it starts up
    • And finally, we gave our container a command (CMD) to run when the container starts.

Image Layers

A Docker image is built up from a series of layers. Each layer represents an instruction in the image’s Dockerfile. Each layer except the last one is read-only. This design principle is important for both security and data management. If someone mistakenly or maliciously changes something in a running container, you can very easily revert back to its original state because the base layers cannot be changed. Or you can simply start a new container instance which will start fresh from your pristine image.

  • Inspect an image
docker image inspect alpine
  • Get the list of layers
docker image inspect --format "{{ json .RootFS.Layers }}" alpine

For the custom image,

docker image inspect --format "{{ json .RootFS.Layers }}" <image ID>

Official Links

Lab: Doing more with Docker Images


Warren

Written by Warren who studies distributed systems at George Washington University. You might wanna follow him on Github