Learning Docker – Reusing images

Welcome to my tutorials on how to leverage Docker to deploy your application! This is meant as much to help me learn, so it doubles as a “what worked for me” series.

In the previous lesson, covered how to add a package using the image’s package manager to add software to an image.

This lesson, we are going to use an image we created as the base for a new image. You will need the image create from the previous lesson for this one.

One of the main benefits of Docker is reusability. If you break out a large project into installed applications and customization layers, then you have the potential to reuse your applications in additional projects. This is fundamentally the way most Docker image cerators operate:

  1. Find a base image that has the application software needed for the project.
  2. Inject customizations to the base to provide the desired functionality, eg, adding source code to an interpreter, like Java, PHP, or Python.
  3. Bake into an image and deploy in a container to confirm that it works as expected, or when ready, for actual use.

However, sometimes you can’t find a base image that suits you. In that case, you can use a low level base image (like ubuntu, busybox, or scratch), and build the core application software your project needs into it. An example of this might be installing a custom compiled version of PHP with support libraries that are not a part of the normal PHP image.

For this lesson, we’re going to use the Python 3 image created in the previous lesson to create a Python application that writes the first 100 Fibonacci numbers. Yes, we could use the Python 3 base image from the Docker Hub, but knowing how you can reuse your own images will allow you to save yourself work by creating reusable images, instead of taking one giant Dockerfile from an old project and reusing it for a new project.

Start by creating a new folder for this project, and create a file called fib.py:

#!/bin/python3
now = 1
last = 0
for count in range(100):
  print (last)
  now, last = now + last, now

If you are on Windows, ensure that you save the file with Unix newlines using a text editor like Notepad++.

Next, make your Dockerfile:

FROM my_python
COPY fib.py /bin
RUN chmod +x /bin/fib.py
CMD [ "fib.py" ]

The RUN chmod statement is a shell command to make the fib.py file executable. If you are on a Linux box creating the image, this needs to be done so the fib.py program can be run as a command (“fib.py”) instead of needing to be run as a Python argument (“python3 fib.py”). And putting this file in /bin puts the program in the container’s PATH, so you don’t need to be in the same folder to call it (or run “./fib.py”). On windows, as a side effect of Windows not using the same permission system as Linux, Docker copies the file over as read and execute ready, which can be a security flaw if you don’t want a file to be run as a program.

Generate and run your image:

docker build -t fib .
docker run --rm -it fib

Seeing some of those big numbers makes me feel like a math wiz.

A couple of things to point out about how the last image and this image work together to make our application. First, only the CMD statement of the run image (the last layer) gets ran with docker run. Remember that from our last lesson, we had CMD ["python3"]. That did not run with this application. We only used the executables and libraries that make Python work from the last image. The second point is that if we update the Python image from our last lesson, it does not instantly update the python used by our application. Instead, our application image is permanently tied to the CURRENT python image available at the time this image was created. In order to update the python that our application uses, we need to recreate the application image after we recreate the Python image.

To summarize, we showed how to use your own, previously built image as a base image for a new project. We covered which CMD statement is used when Docker runs an image. Last, we discussed how your application image will use the version of all parent images that was available when your image was built, and in order to update a dependency in your application, you will need to update the dependencies AND your application image.

For the next lesson, we cover how make a Docker application network accessible.

Tagged :