In this lesson we will cover how to build your own custom Docker image from scratch. We'll walk through the process of starting a Debian container, installing packages and working through configuration issues, as well as a strategy for building a Dockerfile.
You need three things when building custom Docker images. The first is a terminal window to run your commands. The second is a browser window to google and research packages that you need to install. The third is a Scratchpad, an application like TextEdit or Notepad to keep track of commands for building your Docker file.
We're going to first decide what we want to build. There's a port of Nginx called Tengine, that doesn't have a readily available Docker image. Let's start with that. Let's google Tengine to find out a little more about the Web server.
We're now on the Tengine site. Go to the navigation and click download. Here's the file we need to download for our Docker image. Let's go ahead and copy that link address, and go back to our terminal.
What we want to do is build our Docker image from the base Debian image. Let's start by running docker run -it debian bash. What this will do is download the Debian image if it's not already on our machine, and drop you into a BaSH prompt.
Let's try running our command curl . In this case apt tengine-2.2.0.tar.gz. We can see the command is not found. What we want to do is run apt-get to first update our list of repository sources, to make sure we can download the correct package. Then we will run apt-get install -y curl.
Now that has successfully completed, let's keep track of all the commands we run in our Scratchpad. So far, we ran apt-get update, and then we ran apt-get install -y curl. This will make sure we don't forget commands when build our Docker file.
Let's run our previous curl command. Curl is now downloading Tengine to our specified folder and file name. After it's completed downloading, let's go into our app folder. We want to un-tar this Tengine zip file. Let's do tar xef .
Now we can see we have a Tengine-2.2.0 folder. Let's go in that folder and make sure everything un-tarred successfully. We also have to remember to add the lines we ran to our Scratchpad. Let's add the curl line, cd apt, and the tar line. We also want to add the cd to go into this Tengine-2.2.0 folder.
Now, let's go to the Tengine website and google the documentation to find out how we can install this. Go to compiler and install. We can see that there's three lines to install Tengine, configure, make, and make install.
Let's first run start/configure. We get to see the C compiler is not found. What we'll do here is google this to find out how we can install it. I usually prefix searches with apt-get to try to give me the correct name.
In this case, it might look like we need GCC. Let's do apt-get install -y gcc. After that successfully installs, let's add that back to our Scratchpad file. Let's try to run configure again. What we want is this configure line to run successfully.
Here's an error that tells us we're missing the PCRE library. Let's go ahead and google that again. It looks like we need the libpcre3-dev package. Let's go ahead and install that. Let's run configure again.
Now we're missing the OpenSSL library. Since we know the PCRE error has gotten taken care of, let's go ahead and add that to our Scratchpad. Now, let's google this. It looks like we need the libssl-dev package.
Let's go ahead and install that. Then we'll run configure again. Now that that completed successfully, let's go ahead and add that package to our Scratchpad. It looks like Tengine installed in usr/local/nginx. This can be helpful for future reference.
Now that configure has successfully run, let's go ahead and run our make command. We can see, "Make command not found." This batch response is usually solved by typing in apt-get install -y .
Now that make is installed, let's add that back to our Scratchpad. Let's run make again. Let's go back to our install documentation. We see the next line is make install. Let's run that. It looks like Tengine has successfully installed.
Let's go ahead and add those lines back to our Scratchpad file. ./configure make make install. We can see that Tengine was installed in usr/local/nginx. Let's go ahead and go into that folder, and see what's inside.
We could check to see if it's been started by running ps aux. We can see it's not currently running. Let's go ahead and start Nginx or Tengine, by going to /sbin. We can see the executables are right here.
Let's get the full path of our runtime and run it. Now, we can run ps aux again. We can see Nginx or Tengine has started with a master and worker process. Let's take note of this executable path and add it to our Scratchpad file as we'll need it later when we build our Docker file.
Now, we can start building our Docker file. We'll start with the from command, followed with our base image, which is Debian. Next will be our apt-get update, and apt-get install lines. I like to format it like this for readability and for version control purposes.
Let's start with curl, which is up here. We'll go ahead and add the rest of our apt-get packages here. Remember to use suffix every package with a slash so it's included in this install line right here. We'll add gcc, libpcre3-dev, libssl-dev, and make.
Next, will be our curl line to download Tengine. Next, you can't use cd commands within run, because it's not going to be persistent from layer to layer. Let's change our current working directory to apt.
Next, we'll run our unzipping, and then we'll change our working directory again to apt/tengine-2.2.0. I get that from right here. Next will be our configure, make, and make install. For now, let's just keep those all on their own lines.
Finally, we need our executable to run the command. Since this is largely based on Nginx, let's go ahead and google, and see how the official Nginx Docker file handles this. Let's google "Docker Nginx."
We'll scroll down and find the latest stable version of Nginx. Scroll down, and we can see here's the command they do to start Nginx. Let's go ahead and paste this at the end of our Docker file here. We'll replace Nginx with our executable path here.
We also see they're exposing port 80 and 443. Let's go ahead and add that to our file. You notice one other thing they're doing here is forwarding requests to their logs to terminal outputs. Let's go ahead and copy these lines.
The only thing I'm not sure of, there are all these paths for var/log/nginx, and since this is a custom fork of Nginx, let's see if these exist. Let's go to cd var/log. We can see there's no Nginx folder here.
The second place I would check is the installable paths. Let's go back to here. We can see there's a logs directory within here. Let's go into there. We can see here's the access log and the error log. This is the correct directory.
Let's go ahead and replace the var/log/nginx location with our custom path. Now this should be a valid Docker file. Let's go ahead and paste the from, all the way down to the cmd line. Let's exit our running container here and make a Tengine folder.
We'll go into it and create a new file called Docker file. We'll paste the contents of the commands from Notepad into our Docker file here and save the file. Next, we will build our Docker image. Let's run docker build -g, followed by the name of our image.
I'm going to use my name here, followed by /tengine. I'm going to tag this with the version, which I know is 2.2.0, and then space and a dot. What this will do is run all of those commands in succession, and save it into a custom Docker image. If you had any errors building your Docker image, double check your Docker file for typos or errors.
It looks like our image has built successfully. Let's verify by running docker images. We can now see our image, along with the tag and the size. Let's run a container from our new image by typing docker run. Let's expose port 8000 on our host to port 80 in the container, and the name of the image, which is /tengine:2.2.0.
Let's open a new window and check out localhost:8000. We can see "Welcome to Tengine success page" and an access log to output. We know everything is running successfully.