“Why, What, How” Series: Docker — Part 2
Step by Step Docker Implementation with extensive details
To follow along with all the concepts/theories and code discussed in this article, I’d suggest going through the Docker Series Part — 1 and continuing here….
In Part — 2 of the tutorial, we will build our knowledge and get comfortable with different aspects of building, running, and debugging Docker Images and Containers. First, let's install and run the Docker —
For Windows / macOS: https://www.docker.com/products/docker-desktop
For Linux/Ubuntu: https://docs.docker.com/engine/install/ubuntu/
For Windows, Mac Users it’s simply an installation of the docker software from the link given above, and then running the software, it’s free and simple to install. For Linux users, they can setup docker using the sequential CLI commands in the link above. To verify if the installation is successful, go to your terminal and execute the docker command.
Once you’re done with setting up Docker on your machine, now you can work with docker commands on the terminal and manage Docker objects such as images, containers, networks, and volumes via listening to Docker API requests.
Setup Done!
Let’s get our hands dirty now!
Here’s a top-level overview of how we’re going to proceed, if you’re looking for something specific, feel free to jump right in—
- Dockerfile — contains multiple commands you’ll need to learn, very easy to logically understand, structure, and follow with cheat sheets available on GitHub and blogs online.
- Build Docker Image — from the Dockerfile created, build an image with a plethora of options such as Image and Version(tag) naming, saving image id to a file for future use, custom host IP, setting metadata, cache or no-cache, and many more…
- Run Docker Image — from the Image created above, we run a docker container that gives the output from the Dockerfile or the application we executed at the end of running the docker
- Controlling Images and Containers — once you’ve built multiple images and are actively running multiple containers, docker provides simple commands to control ( start, stop, remove, customize) them as and when needed
Dockerfile -
Create a file on any text editor or IDE called “Dockerfile” and start coding-
Step by Step Instructions to build the Dockerfile, key pointers —
Step 1: FROM
Start with building a base Image with the keyword “FROM”. You can use a lightweight OS (example: alpine) image, or Ubuntu, Kali Linux, etc. which docker pulls from Docker Hub to build the base image and then keep adding other tools ( If you’re confused about pulling an image from Docker Hub while building a Dockerfile, every software package or tool such as MongoDB, Python, nodeJS is an Image on DockerHub, so when we build a Docker image, we use these multiple images and consecutively aggregate them together to setup our application infrastructure )
# Comments are enabled using #
# Getting the base Image
# alternative : "FROM scratch" -> Empty base image
FROM ubuntu:latest
Step 2: LABEL
This is where you add your name ( usually your docker id, that you used to sign up to DockerHub or something cool ), email address, organization name, etc. The “LABEL” keyword was earlier called “MAINTAINER”, which is now deprecated
# Label (optional) to keep track of author
LABEL pranjalbiyani <pranjalbiyani1996@gmail.com>
Step 3: RUN and CMD
The “RUN” instruction will execute commands in a new layer on top of the current image (right now, base alpine) and commit the results. The resulting committed image will be used for the next step in the Dockerfile.
In this dockerfile, The “CMD” instruction is to validate if everything is working fine, basically, if Python3 is installed and ready to use on your container.
Note: You can only have one “CMD” instruction which gets executed only when you run the container ( with the Docker image you’re going to create ), whereas “RUN” instructions can be called multiple times where you can either have a single “RUN” instruction with multiple instructions separated by “&&” or new lines with the “RUN” instruction
# Executing intial set of commands after the ubuntu image is built
# RUN commands get executed upon creation of the image
RUN apt-get update && apt-get install -y python3-pip
RUN apt-get install -y python3
# For alpine,package manager would be "apk", in place of apt-get
# CMD commands get executed only after running images as containers
CMD ["python3","--version"]
And that’s it ! You’re having a great start —
With the above Dockerfile, you’re all set to build and run your first container
Let’s build a Docker Image with this Dockerfile —
Note : Docker CLI management commands start with docker, then a space, then the management category, then a space, and then the command. For example, docker container stop ,stops a container.
We build with the —
“docker build” command
We run with the —
“docker run” command
By default, docker knows to build images using the file named as Dockerfile, without any extension, so ensure that your instructions are written in a file called “Dockerfile”, most IDE’s recognise the file without any hassle or external extensions.
Now, the docker build command needs an argument, the location of your dockerfile, for example if your dockerfile is in the same repository as your command line, you could simply build using the command
# If "Dockerfile" is in the same repository
$ docker build .
# If "Dockerfile" is in a different folder, say "test"
$ docker build test/.
Minor inconvenience — 😅, when you build images using the command above, docker names the images you create as Image ID’s which look something like this —
We have a solution — the “-t” (tag) argument, it lets you appropriately name the repository and tag in the format “<repository>:<tag>” format, so —
$ docker build -t test:1.0.0 .
The tag also helps you when you want to run a container using the docker image —
$ docker run test:1.0.0
# In the other case, you'd have to use
$ docker run 3809ecb11f99
The output of running the commands above on your terminal will be the following — which is basically the CMD execution of “python3 — version”
Done, You’ve successfully created, built, and run!
Now let’s learn to control the Images and Containers
Image Control —
List all Images —
$ docker images
Delete an Image using Image ID —
# Using Image ID
$ docker rmi a0a6b8385f81
# Using <Repository>:<tag>
$ docker rmi test1:1.0.1
Delete all Images —
“docker images -aq” uses 2 arguments “-a” for all and “-q” for quiet (only Image IDs )
# The following command only works if none of the images have running containers associated with them
$ docker rmi $(docker images -aq)
# If any container is running attached to an image -
$ docker rmi -f $(docker images -aq) # -f is to force deletion
Container Control —
List all containers —
Once the CMD [“python3”, “ — version”] of the Dockerfile statement is executed upon running the docker run command, the container stops, since it’s finished its task list from the dockerfile. That’s why it shows the Exited (0) STATUS in the screenshot below.
# docker container ls,shows only the running containers,-a shows all
$ docker container ls -a
Delete a container —
# To delete stopped
$ docker rm <CONTAINER ID>
# To stop a running container, we use docker kill
# We shall explore that in the next article Part - 3
Delete all containers—
# Note : all these containers are stopped
$ docker container rm $(docker ps -aq)
Note : docker stop and docker kill , both the commands stop a container, but stop leads to a safe exit,whereas kill is unsafe. Basically, when stop doesn’t work, we use kill
And……
We’re done for Part-2 of the Docker Series
Part — 3 Coming Soon
Behold Part — 3
- We build an ML Model from scratch
- Build a Flask API to serve the Frontend
- Build the front-end HTML for its usage
- Integrate all 3
- Dockerize it with all the requirements for execution
- Explore other docker commands for perfection
- Test it by running on different machines to reap the benefits of Docker