Skip to content

Instantly share code, notes, and snippets.

@evanscottgray
Last active July 28, 2017 09:47
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save evanscottgray/7815726a2b8160cacf48 to your computer and use it in GitHub Desktop.
Save evanscottgray/7815726a2b8160cacf48 to your computer and use it in GitHub Desktop.
Creating a Base Image for the Lab

Building a new Base Image

Practical documentation on how to create a new base image.

Pick a Base Image to work on.

First we'll want to identify what image we are going to use as our base image to modify is.

In this example our previous base image is old-oca-bastion.

Define a Goal

We have been tasked with doing the following:

  1. install the package openjdk-7-jre
  2. Deleting the directory /opt/wowmistake that contains the 10 gb file mistake.file that was mistakenly added to old-oca-bastion

When we are done, we should end up with an image called new-oca-bastion-flat.

Start Working with our old Base Image...

We'll want to start up a copy of the old base image so that we can start modifying it with the goal of adding the openjdk-7-jre package, and deleting the large and unneeded file from it.

The following command will spawn a new instance of our old base image old-oca-bastion, and pop us into an interactive bash session from which we can make changes:

# On Container Host
#
# Starting with the -t and -i flags will cause docker to create an
#  interactive terminal session and attach us to it.
#
# We use the privileged flag to allow us to install packages that require making
#  devices, nodes, etc.
#
# Giving our container a name with the --name flag allows us
#  to interact with it later in a simple way.
docker run -t -i --privileged=true --name='canvas-container' old-oca-bastion /bin/bash

Once we're in this image, we can go ahead and install the openjdk-7-jre package as requested.

# Inside Container
apt-get update
apt-get install -y openjdk-7-jre

Let's pretend that after installing the openjdk-7-jre package, we have to take care of urgent business and our session with the container is somehow interrupted.

We can get back into the container we were previously modifying like this:

# On Container Host
#
# The -i -a arguments appended to docker start allow us to start an interactive session.
docker start -i -a canvas-container

This will pop us back into an interactive session with the container we were previously modifying. Running which java should confirm this by showing us that the openjdk-7-jre package we installed a while ago is still there.

Let's go ahead and remove that /opt/wowmistake directory that contains the 10gb file mistake.file now.

# Inside Container
rm -rf /opt/wowmistake

We could just exit now and docker commit the canvas-container as a new base image, but we have to remember that we want to trim this image down as much as possible before creating a base image from it.

Start with these commands that will clear out the trash that apt-get and apt leaves behind when installing new packages:

# Inside Container
apt-get clean
rm -rf /var/lib/apt/lists/*

Let's take some time to poke around the container for large files that we don't need. We don't want to have to go through this whole process again to get rid of a mistake.file if we can help it.

This will give us a list of the 100 largest files in the container.

# Inside Container
find / -type f -printf '%s %p\n'| sort -nr | head -100

If we see something that is obviously not needed and can be deleted, do so.

Next let's go ahead and clear out every user's home directory.

# Inside Container
rm -rf /home/*

Then clear out /var/log of all log files.

# Inside Container
find /var/log -type f -delete

Then finally, we'll clear out our /root/.bash_history and exit.

# Inside Container
history -c && exit

Create A Flat Base Image From The canvas-container

Using the magic of docker export and docker import, we take the filesystem of the canvas-container container, convert it to a tar file, then dynamically import the tar file to a Docker Image that contains the entire filesystem of the canvas-container squished down to a single layer.

# On Container Host
docker export canvas-container | docker import - new-oca-bastion-flat

Looking at the output of:

# On Container Host
docker images --tree | grep -C 8 new-oca-bastion-flat

We can see that the filesystem only has 1 layer, and is quite small:

├─e8779f4aec7e Virtual Size: 1.90 GB Tags: new-oca-bastion-flat:latest

This method of creating base containers is much better than simply doing the standard docker commit because it is 1 layer in size.

Why Flat Is Better For Base Images

If for example we were to:

# On Container Host
docker commit canvas-container new-oca-bastion-not-flat

And the image that canvas-container was started from had a large history, the output of:

# On Container Host
docker images --tree | grep -B 20 new-oca-bastion-not-flat

Could end up looking something like this:

└─463b8f0dff7c Virtual Size: 4.498 GB
  └─f618caf34ebc Virtual Size: 4.498 GB
    └─9e7e859c80e6 Virtual Size: 4.556 GB Tags: wow-image:latest
      └─75242272e6dd Virtual Size: 4.556 GB
        └─279b4553818c Virtual Size: 4.57 GB
          └─1211e6623116 Virtual Size: 4.57 GB
            └─1a13d179d39d Virtual Size: 4.57 GB
              └─f8b5f68495ea Virtual Size: 5.662 GB
                └─05f60a45ab23 Virtual Size: 5.662 GB
                  └─6442b9180e4b Virtual Size: 5.662 GB
                    └─f7d9c4627b6e Virtual Size: 5.662 GB
                      └─b4c6fba9f6e3 Virtual Size: 5.662 GB
                        └─eaeb85aac1ac Virtual Size: 5.804 GB Tags: some-image:latest
                          ├─6f4417959152 Virtual Size: 5.804 GB
                            └─e3caad62bdbd Virtual Size: 5.804 GB
                              ├─2a9fd632f5f5 Virtual Size: 6.439 GB
                                └─39fbe6cb5d2d Virtual Size: 6.439 GB
                                  └─b4f4ebc85ac4 Virtual Size: 6.439 GB Tags: old-image:latest
                                    └─0ae3b1019fde Virtual Size: 16.439 GB Tags: old-oca-bastion:latest
                                      └─7186b8e4b3dc Virtual Size: 6.439 GB Tags: new-oca-bastion-not-flat

As a result of this, every time we want to push out this new-oca-bastion-not-flat image, Docker has to try and send all of the extra layers, and every time we try to run the new-oca-bastion-not-flat image, Docker has to assemble all of the layers before starting the container.

We're done!

That's all there is to it, we can now use our new-oca-bastion-flat image for new builds!

It also might be a good idea to push the new base to the registry...

# On Container Host
docker tag new-oca-bastion-flat 10.6.195.13:5000/new-oca-bastion-flat
docker push 10.6.195.13:5000/new-oca-bastion-flat
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment