http://127.0.0.1:8080
in the browser, you'll see a default response page.custom-nginx
in there. Now, create a new file named Dockerfile
inside that directory. A Dockerfile
is a collection of instructions that once processed by the daemon, results into an image. Content for the Dockerfile
is as follows:Dockerfile
starts with a FROM
instruction. This instruction sets the base image for your resultant image. By setting ubuntu:latest
as the base image here, you get all the goodness of Ubuntu already available in your custom image hence, you can use things like the apt-get
command for easy package installation.EXPOSE
instruction is used to indicate the port that needs to be published. Using this instruction doesn't mean that you won't need to --publish
the port. You'll still need to use the --publish
option explicitly. This EXPOSE
instruction works like a documentation for someone who's trying to run a container using your image. It also has some other usages that I won't be discussing here.RUN
instruction in a Dockerfile
executes a command inside the container shell. The apt-get update && apt-get install nginx -y
command checks for updated package versions and installs NGINX. The apt-get clean && rm -rf /var/lib/apt/lists/*
command is used for clearing the package cache because you don't want any unnecessary baggage in your image. These two commands are simple Ubuntu stuff, nothing fancy. The RUN
instructions here, are written in shell
form. These can also be written in exec
form. You can consult the official reference for more information.CMD
instruction sets the default command for your image. This instruction is written in exec
form here comprising of three separate parts. Here, nginx
refers to the NGINX executable. The -g
and daemon off
are options for NGINX. Running NGINX as a single process inside containers is considered a best practice hence the usage of this option. The CMD
instruction can also be written in shell
form. You can consult the official reference for more information.Dockerfile
you can build an image out of it. Just like the container related commands, the image related commands can be issued using the following syntax:Dockerfile
you just wrote, open up your terminal inside the custom-nginx
directory and execute the following command:Dockerfile
and the build context. In the issued command above:docker image build
is the command for building the image. The daemon finds any file named Dockerfile
within the context..
at the end sets the context for this build. The context means the directory accessible by the daemon during the build process.container run
command coupled with the image ID that you received as the result of the build process. In my case the id is 3199372aa3fc
evident by the Successfully built 3199372aa3fc
line in the previous code block.http://127.0.0.1:8080
and you should see the default response page.--tag
or -t
option is used in such cases. Generic syntax for the option is as follows:docker container run mysql:5.7
where mysql
is the image repository and 5.7
is the tag.custom-nginx:packaged
you can execute the following command:custom-nginx:packaged
instead of some long random string.image tag
command to do that:container ls
command, you can use the image ls
command to list all the images in your local system:image rm
command. The generic syntax is as follows:custom-nginx:packaged
image, you may execute the following command:image prune
command to cleanup all un-tagged dangling images as follows:--force
or -f
option skips any confirmation questions. You can also use the --all
or -a
option to remove all cached images in your local registry.custom-nginx:packaged
image from the previous sub-section.image history
command. The various layers of the custom-nginx:packaged
image can be visualized as follows:d70eaf7277ea
to 7f16387f7307
image. I'll ignore the bottom four layers where the IMAGE
is <missing>
as they are not of our concern.Dockerfile
will create a layer in the image.d70eaf7277ea
was created by /bin/sh -c #(nop) CMD ["/bin/bash"]
which indicates that the default shell inside Ubuntu has been loaded successfully.6fe4e51e35c1
was created by /bin/sh -c #(nop) EXPOSE 80
which was the second instruction in your code.587c805fe8df
was created by /bin/sh -c apt-get update && apt-get install nginx -y && apt-get clean && rm -rf /var/lib/apt/lists/*
which was the third instruction in your code. You can also see that this image has a size of 60MB
given all necessary packages were installed during the execution of this instruction.7f16387f7307
was created by /bin/sh -c #(nop) CMD ["nginx", "-g", "daemon off;"]
which sets the default command for this image.FROM
, EXPOSE
, RUN
and CMD
instructions. In this sub-section you'll be learning a lot more about other instructions.apt-get
in the previous example.nginx-1.19.2.tar.gz
inside the custom-nginx
directory. You'll use this archive as the source for building NGINX.nginx-1.19.2.tar.gz
file inside the image.make
tool.nginx
executable.Dockerfile
and update its contet as follows:Dockerfile
reflects the seven steps I talked about beforehand.FROM
instruction sets Ubuntu as the base image making an ideal environment for building any application.RUN
instruction installs standard packages necessary for building NGINX from source.COPY
instruction here is something new. This instruction is responsible for copying the the nginx-1.19.2.tar.gz
file inside the image. The generic syntax for the COPY
instruction is COPY <source> <destination>
where source is in your local filesystem and the destination is inside your image. The .
as the destination means the working directory inside the image which is by default /
unless set otherwise.RUN
instruction here extracts the contents from the archive using tar
and gets rid of it afterwards.nginx-1.19.2
containing the source code. Hence on the next step, you'll have to cd
inside that directory and perform the build process. You can read the How to Install Software from Source Code⦠and Remove it Afterwards article at It's Foss to learn more on the topic.nginx-1.19.2
directory using rm
command.nginx-1.19.2.tar.gz
, you can create an argument using the ARG
instruction. This way, you'll be able to change the version or filename by just changing the argument.COPY
called the ADD
instruction which is capable of adding files from the internet.Dockerfile
file and update it's content as follows:ARG
on line 13, 14 and the usage of the ADD
instruction on line 16. Explanation for the updated code is as follows:ARG
instruction lets you declare variables like in other languages. These variables or arguments can later be accessed using the ${argument name}
syntax. Here, I've put the filename nginx-1.19.2
and the file extension tar.gz
in two separate arguments. This way I can switch between newer versions of NGINX or the archive format by making a change in just one place. In the code above, I've added default values to the variables. Variable values can be passed as options of the image build
command as well. You can consult the official reference for more details.ADD
instruction, I've formed the download URL dynamically using the arguments declared above. The https://nginx.org/download/${FILENAME}.${EXTENSION}
line will result in something like https://nginx.org/download/nginx-1.19.2.tar.gz
during the build process. You can change the file version or the extension by changing it in just one place thanks to the ARG
instruction.ADD
instruction doesn't extract files obtained from the internet by default hence, the usage of tar
on line 18.custom-nginx:built-v2
image.custom-nginx:built-v2
image has been successfully run. The container should be accessible at http://127.0.0.1:8080
address now.image ls
command:Dockerfile
first:RUN
instruction installs a lot of stuff. Although these packages are necessary for building NGINX from source, they are not necessary for running it. Out of the 6 packages that we installed, only two are necessary for running NGINX. These are libpcre3
and zlib1g
. So a better idea can be to uninstall the other packages once the build process is done.Dockerfile
as follows:RUN
instruction is doing all the necessary heavy-lifting. The exact chain of events is as follows:libpcre3
and zlib1g
packages are needed for running NGINX hence they're kept.RUN
instruction instead of nicely splitting them into multiple instructions, like we did previously. Well that's a mistake. If you install packages and then remove them in separate RUN
instructions, they'll live in separate layers of the image. Although the final image will not have the removed packages, their size will still be added to the final image given they exist in one of the layers consisting the image. So make sure you make these kind of changes on a single layer.Dockerfile
and see the differences.musl
libc
and busybox
and is lightweight. Where the latest ubuntu image weighs at around 28MB, alpine is 2.8MB. Apart from the lightweight nature, Alpine is also secure and is a much better fit for creating containers than the other distributions.custom-nginx
image by using the alpine image as its base.Dockerfile
and update its content as follows:apt-get install
for installing packages, we use apk add
and the --no-cache
option means that the downloaded package won't be cached. Likewise apk del
is used instead of apt-get remove
to uninstall packages.--virtual
option for apk add
command is used for bundling a bunch of packages into a single virtual package for easier management. Packages that are needed only for building the program is labeled as .build-deps
which is then removed on line 29 by executing apk del .build-deps
command. You can learn more about virtuals in the official docs.Dockerfile
and see the difference in file size:apk
package manager, there are some other things that differ in Alpine from Ubuntu but they're not that much of big deal. You can just search the internet whenever you get stuck.rmbyext
application resides inside the sub-directory with the same name.Dockerfile
take a moment to plan out what the final output should be. In my opinion it should be like something as follows:rmbyext
script.rmbyext
script should be set as the entrypoint so the image can take extension names as arguments.rmbyext
as the entry-point for this image.Dockerfile
inside the rmbyext
directory and put following code in it:FROM
instruction sets python as the base image making an ideal environment for running python scripts. The 3-alpine
tag indicates that you want the Alpine variant of Python 3.WORKDIR
instruction sets the default working directory to /zone
here. The name of the working directory is completely random here. I found zone to be a fitting name, you may use anything you want.rmbyext
script is installed from GitHub, git
is an install time dependency. The RUN
instruction on line 5 installs git
then installs the rmbyext
script using git and pip. It also gets rid of git
afterwards.ENTRYPOINT
instruction sets the rmbyext
script as the entry-point for this image.latest
by default. You should be able to run the image as you saw in the previous section. Remember to refer to the actual image name you've set, instead of fhsinchy/rmbyext
here.--tag
or -t
option is as follows:custom-nginx
image online. To do so, open up a new terminal window inside the custom-nginx
project directory. To share an image online, you'll have to tag it following the <docker hub username>/<image name>:<image tag>
syntax. My username is fhsinchy
so the command will look like as follows:fhsinchy/custom-nginx
is the image repository and latest
is the tag. The image name can be anything you want and can not be changed once you've uploaded the image. The tag can be changed whenever you want and usually reflects the version of the software or different kind of builds.node
image as an example. The node:lts
image refers to the long term support version of Node.js whereas the node:lts-alpine
version refers to the Node.js version built for Alpine Linux which is much smaller than the regular one.latest
. But that doesn't mean that the latest
tag will always refer to the latest version. If for some reason you explicitly tag an older version of the image as latest
then Docker will not make any extra effort to cross check that.