Sunday, 9 November 2025

Docker - Dockerfile - create image - spin up container from it - pull the change to docker hub

Dockerfile

A Dockerfile is a text file that contains all the commands a user could call on the command line to assemble an image.

Most common instructions used in a Dockerfile and their primary purposes is below 


InstructionPurpose
FROMSpecifies the base image to start the build process. Must be the first non-comment instruction.
RUNExecutes a command in a new layer on top of the current image. Used for installing packages, compiling code, etc.
WORKDIRSets the working directory for any RUN, CMD, ENTRYPOINT, COPY, or ADD instructions that follow it.
COPYCopies new files or directories from the host machine into the image's filesystem at a specified destination.
ADDSimilar to COPY, but can also handle local tar file extraction and remote URL fetching. COPY is generally preferred.
EXPOSEInforms Docker that the container listens on the specified network ports at runtime. (Doesn't publish the port).
CMDProvides defaults for an executing container. Only the last CMD in a Dockerfile will be executed.
ENTRYPOINTConfigures a container that will run as an executable. Often used to wrap the application's executable.
ENVSets environment variables (key-value pairs) inside the image.

In the previous exercise, we created an Apache web server. Now, suppose we want to set up an NGINX website using the same static HTML files that were used with the Apache web server. We can do this by building a custom NGINX image.


1. Create a docker file with below content 


[root@devopsvm01 ~]# mkdir -p /root/dockerfile/

[root@devopsvm01 ~]# cd /root/dockerfile/

[root@devopsvm01 dockerfile]# ls -lrt

total 4

-rw-r--r--. 1 root root 526 Nov  3 11:39 Dockerfile

[root@devopsvm01 dockerfile]# cat Dockerfile


# 1. FROM: Start with a lightweight Nginx image

FROM nginx:stable-alpine


# 2. WORKDIR: Set the working directory. 

WORKDIR /usr/share/nginx/html


# 3. RUN: rename the default, placeholder Nginx index page from WORKDIR 

RUN mv index.html index_nginx.html


# 4. COPY: Copy the static HTML files into the default web root

COPY *.html .


# 5. EXPOSE: Inform Docker that the container listens on port 80

EXPOSE 80


# 6. CMD: Default command to start the Nginx server in the foreground

CMD ["nginx", "-g", "daemon off;"]

[root@devopsvm01 dockerfile]#


Note: Once you use the WORKDIR instruction in a Dockerfile, any subsequent instruction that involves a path—such as RUN, CMD, ENTRYPOINT, COPY, or ADD—will interpret a single period (.) as a reference to the directory path you set with WORKDIR.

nginx:stable-alpine → tells Docker to use the official Nginx image from Docker Hub, specifically the stable version that is built on Alpine Linux.

CMD ["nginx", "-g", "daemon off;"] -→ "nginx" is the executable program (the Nginx web server application itself) that Docker will start, and  "daemon off;" is the specific configuration directive passed globally. By default, Nginx is designed to run in the background as a daemon process on a traditional server. However, Docker containers are designed to run only one primary process that stays in the foreground. This directive tells Nginx to stay in the foreground

2. Copy your html files from the default apache web root directory (/var/www/html/)

[root@devopsvm01 dockerfile]# cd /var/www/html/

[root@devopsvm01 html]# ls -lrt
total 88
-rw-r--r--. 1 root root  3561 Nov  2 09:20 about.html
-rw-r--r--. 1 root root  3081 Nov  2 09:40 index.html
-rw-r--r--. 1 root root  2459 Nov  2 17:21 services.html
-rw-r--r--. 1 root root    11 Nov  2 17:21 main.html
-rw-r--r--. 1 root root  3171 Nov  2 19:10 product.html
-rw-r--r--. 1 root root  1390 Nov  2 19:10 news.html
-rw-r--r--. 1 root root  2835 Nov  3 02:29 offer.html
[root@devopsvm01 html]#
[root@devopsvm01 html]# cp *.html /root/dockerfile/
[root@devopsvm01 html]# cd /root/dockerfile/
[root@devopsvm01 dockerfile]# ls -lrt
total 32
-rw-r--r--. 1 root root  526 Nov  3 11:39 Dockerfile
-rw-r--r--. 1 root root 3561 Nov  3 11:40 about.html
-rw-r--r--. 1 root root 3081 Nov  3 11:40 index.html
-rw-r--r--. 1 root root 2459 Nov  3 11:40 services.html
-rw-r--r--. 1 root root 3171 Nov  3 11:40 product.html
-rw-r--r--. 1 root root 2835 Nov  3 11:40 offer.html
-rw-r--r--. 1 root root 1390 Nov  3 11:40 news.html
-rw-r--r--. 1 root root   11 Nov  3 11:40 main.html
[root@devopsvm01 dockerfile]#


3. Now create your custom image using docker build

docker build -t <IMAGE_NAME>:<TAG> <PATH_TO_DOCKERFILE>

[root@devopsvm01 dockerfile]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED                  SIZE
nginx         latest    d261fd19cb63   Less than a second ago   152MB
ubuntu        latest    97bed23a3497   4 weeks ago              78.1MB
hello-world   latest    1b44b5a3e06a   2 months ago             10.1kB
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@devopsvm01 dockerfile]#


[root@devopsvm01 dockerfile]# docker build -t my-nginx-site:version-1 .
[+] Building 8.7s (9/9) FINISHED                                                                                                                                                                                              docker:default
 => [internal] load build definition from Dockerfile                                                                                                                                                                                    0.0s
 => => transferring dockerfile: 626B                                                                                                                                                                                                    0.0s
 => [internal] load metadata for docker.io/library/nginx:stable-alpine                                                                                                                                                                  0.8s
 => [internal] load .dockerignore                                                                                                                                                                                                       0.0s
 => => transferring context: 2B                                                                                                                                                                                                         0.0s
 => [1/4] FROM docker.io/library/nginx:stable-alpine@sha256:30f1c0d78e0ad60901648be663a710bdadf19e4c10ac6782c235200619158284                                                                                                            5.5s
 => => resolve docker.io/library/nginx:stable-alpine@sha256:30f1c0d78e0ad60901648be663a710bdadf19e4c10ac6782c235200619158284                                                                                                            0.1s
 => => sha256:09ab424a8c788f8d0fe3a64429f6d19dfa526885c8609b748d0943a75dcb9f8c 2.49kB / 2.49kB                                                                                                                                          0.0s
 => => sha256:8e049f0fd1511eaabb03da73d0582501fd3a012ddb00620ff653b1a13b646310 627B / 627B                                                                                                                                              1.2s
 => => sha256:30f1c0d78e0ad60901648be663a710bdadf19e4c10ac6782c235200619158284 10.32kB / 10.32kB                                                                                                                                        0.0s
 => => sha256:c318e336065b17ff460aeac6d14bce5d0b13e35f25d5cb1843b635359fc00c9a 10.77kB / 10.77kB                                                                                                                                        0.0s
 => => sha256:f637881d1138581d892d9eb942c56e0ccc7758fe3bdc0f1e6cd66059fdfd8185 3.64MB / 3.64MB                                                                                                                                          0.8s
 => => sha256:b8554c5f1ad0265d1dc3a5f23b3b52e93fa1cdeda0c6b54618d3f9168e6ed01b 1.79MB / 1.79MB                                                                                                                                          1.2s
 => => extracting sha256:f637881d1138581d892d9eb942c56e0ccc7758fe3bdc0f1e6cd66059fdfd8185                                                                                                                                               0.3s
 => => sha256:71a39d0d04b2893246ec57f9cf1b074a63fd0f094098a8b1741d0e625f4009c1 955B / 955B                                                                                                                                              1.6s
 => => extracting sha256:b8554c5f1ad0265d1dc3a5f23b3b52e93fa1cdeda0c6b54618d3f9168e6ed01b                                                                                                                                               0.4s
 => => sha256:e6918dcfd20da0647335265f4647268123ce772646f9dea11cae650f26be0276 404B / 404B                                                                                                                                              2.0s
 => => sha256:c4fca37af7b3b885e76d1a14e76d630444c2868b27ff67848e077142d9771faa 1.21kB / 1.21kB                                                                                                                                          1.8s
 => => sha256:bc1d7488b05ed88bc5975378fd4ef0f1ea4b6114d13fa5cbeec6a572588e0c00 1.40kB / 1.40kB                                                                                                                                          2.2s
 => => extracting sha256:8e049f0fd1511eaabb03da73d0582501fd3a012ddb00620ff653b1a13b646310                                                                                                                                               0.0s
 => => extracting sha256:71a39d0d04b2893246ec57f9cf1b074a63fd0f094098a8b1741d0e625f4009c1                                                                                                                                               0.0s
 => => sha256:3e300a7cb18c79c3ddadf170ae2c540c8feafdf7fcdc6cd5d5a3cd229fb0cada 15.55MB / 15.55MB                                                                                                                                        4.0s
 => => extracting sha256:e6918dcfd20da0647335265f4647268123ce772646f9dea11cae650f26be0276                                                                                                                                               0.0s
 => => extracting sha256:c4fca37af7b3b885e76d1a14e76d630444c2868b27ff67848e077142d9771faa                                                                                                                                               0.0s
 => => extracting sha256:bc1d7488b05ed88bc5975378fd4ef0f1ea4b6114d13fa5cbeec6a572588e0c00                                                                                                                                               0.0s
 => => extracting sha256:3e300a7cb18c79c3ddadf170ae2c540c8feafdf7fcdc6cd5d5a3cd229fb0cada                                                                                                                                               1.1s
 => [internal] load build context                                                                                                                                                                                                       0.1s
 => => transferring context: 17.21kB                                                                                                                                                                                                    0.0s
 => [2/4] WORKDIR /usr/share/nginx/html                                                                                                                                                                                                 0.1s
 => [3/4] RUN mv index.html index_nginx.html                                                                                                                                                                                            0.8s
 => [4/4] COPY *.html .                                                                                                                                                                                                                 0.2s
 => exporting to image                                                                                                                                                                                                                  1.0s
 => => exporting layers                                                                                                                                                                                                                 1.0s
 => => writing image sha256:5fbef17336dda4969357a50be691c93f16e8f6606f5939f72231d57aa0a1cd3a                                                                                                                                            0.0s
 => => naming to docker.io/library/my-nginx-site:version-1                                                                                                                                                                              0.0s
[root@devopsvm01 dockerfile]#


[root@devopsvm01 dockerfile]# docker images
REPOSITORY      TAG         IMAGE ID       CREATED                  SIZE
nginx           latest      d261fd19cb63   Less than a second ago   152MB
my-nginx-site   version-1   5fbef17336dd   26 seconds ago           48.3MB
ubuntu          latest      97bed23a3497   4 weeks ago              78.1MB
hello-world     latest      1b44b5a3e06a   2 months ago             10.1kB
[root@devopsvm01 dockerfile]#

4. Lets spin up a new container from the image that we just created.

[root@devopsvm01 dockerfile]# docker run --name my-nginx-site -d -p 8081:80 my-nginx-site
Unable to find image 'my-nginx-site:latest' locally

docker: Error response from daemon: pull access denied for my-nginx-site, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

Run 'docker run --help' for more information
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]#


When you use just the repository name (my-nginx-site), Docker automatically assumes the tag is :latest. It then tried to find a local image named my-nginx-site:latest. Since my-nginx-site:latest wasn't found locally, Docker tried to pull it from Docker Hub, which resulted in the "pull access denied" error because it's a private, custom image that doesn't exist on the public registry.

To fix this, you need to explicitly include the :version-1 tag in your docker run command:


[root@devopsvm01 dockerfile]# docker run --name my-nginx-site-container -d -p 8081:80 my-nginx-site:version-1
e86eda2ef3b05b455dd3f4f8fe838fae9de084d1710d9e9c6639e781d346f363
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]# docker ps
CONTAINER ID   IMAGE                     COMMAND                  CREATED         STATUS         PORTS                                     NAMES
e86eda2ef3b0   my-nginx-site:version-1   "/docker-entrypoint.…"   7 seconds ago   Up 6 seconds   0.0.0.0:8081->80/tcp, [::]:8081->80/tcp   my-nginx-site-container
[root@devopsvm01 dockerfile]#


5. Access your website. 




























let's try to access the default webpage that we renamed 



















6. Push the image to docker hub

[root@devopsvm01 dockerfile]# docker login -u mahekarthya

i Info → A Personal Access Token (PAT) can be used instead.
         To create a PAT, visit https://app.docker.com/settings


Password:

WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/

Login Succeeded
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]# docker images
REPOSITORY      TAG         IMAGE ID       CREATED                  SIZE
nginx           latest      d261fd19cb63   Less than a second ago   152MB
my-nginx-site   version-1   5fbef17336dd   33 minutes ago           48.3MB
ubuntu          latest      97bed23a3497   4 weeks ago              78.1MB
hello-world     latest      1b44b5a3e06a   2 months ago             10.1kB
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]# docker push my-nginx-site
Using default tag: latest
The push refers to repository [docker.io/library/my-nginx-site]
tag does not exist: my-nginx-site:latest
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]# docker push my-nginx-site:version-1
The push refers to repository [docker.io/library/my-nginx-site]

a9fa5449d399: Preparing
2d9363c58513: Preparing
5f70bf18a086: Preparing
90ec27130398: Preparing
a231a657395e: Preparing
5f23a9cf34f1: Waiting
7d9abb9ab3b7: Waiting
34034c523565: Waiting
570a1c87f279: Waiting
412e147b334c: Waiting
922ec217407c: Waiting
denied: requested access to the resource is denied
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]#

This is because docker think my-nginx-site is an official image, not your personal repo. You must tag your image with your Docker Hub username before pushing.


[root@devopsvm01 dockerfile]# docker push mahekarthya/my-nginx-site:version-1
The push refers to repository [docker.io/mahekarthya/my-nginx-site]
An image does not exist locally with the tag: mahekarthya/my-nginx-site
[root@devopsvm01 dockerfile]#

Docker looks for a local image that already has the exact same name and tag, so tag it.


[root@devopsvm01 dockerfile]# docker tag my-nginx-site:version-1 mahekarthya/my-nginx-site:version-1
[root@devopsvm01 dockerfile]#

[root@devopsvm01 dockerfile]# docker images
REPOSITORY                  TAG         IMAGE ID       CREATED                  SIZE
nginx                       latest      d261fd19cb63   Less than a second ago   152MB
my-nginx-site               version-1   5fbef17336dd   40 minutes ago           48.3MB
mahekarthya/my-nginx-site   version-1   5fbef17336dd   40 minutes ago           48.3MB
ubuntu                      latest      97bed23a3497   4 weeks ago              78.1MB
hello-world                 latest      1b44b5a3e06a   2 months ago             10.1kB
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]#

[root@devopsvm01 dockerfile]# docker push mahekarthya/my-nginx-site:version-1
The push refers to repository [docker.io/mahekarthya/my-nginx-site]
a9fa5449d399: Pushed
2d9363c58513: Pushed
5f70bf18a086: Pushed
90ec27130398: Pushed
a231a657395e: Pushed
5f23a9cf34f1: Pushed
7d9abb9ab3b7: Pushed
34034c523565: Pushed
570a1c87f279: Pushed
412e147b334c: Pushed
922ec217407c: Pushed
version-1: digest: sha256:8ff328ae3701d92dbff9e3c85352cf5bf1b2da23739b9e3731ce6eacb1037e17 size: 2610
[root@devopsvm01 dockerfile]#

You can see your image in docker hub













7. Let's remove the container and image and then pull the image.

Make sure you are still logged in to docker hub.

[root@devopsvm01 dockerfile]# docker stop e86eda2ef3b0
e86eda2ef3b0
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]#  docker rm e86eda2ef3b0
e86eda2ef3b0
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@devopsvm01 dockerfile]#



[root@devopsvm01 dockerfile]# docker images
REPOSITORY                  TAG         IMAGE ID       CREATED                  SIZE
nginx                       latest      d261fd19cb63   Less than a second ago   152MB
my-nginx-site               version-1   5fbef17336dd   49 minutes ago           48.3MB
mahekarthya/my-nginx-site   version-1   5fbef17336dd   49 minutes ago           48.3MB
ubuntu                      latest      97bed23a3497   4 weeks ago              78.1MB
hello-world                 latest      1b44b5a3e06a   2 months ago             10.1kB
[root@devopsvm01 dockerfile]# docker rmi 5fbef17336dd
Error response from daemon: conflict: unable to delete 5fbef17336dd (must be forced) - image is referenced in multiple repositories
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]# docker rmi my-nginx-site:version-1
Untagged: my-nginx-site:version-1
[root@devopsvm01 dockerfile]# docker rmi mahekarthya/my-nginx-site:version-1
Untagged: mahekarthya/my-nginx-site:version-1
Untagged: mahekarthya/my-nginx-site@sha256:8ff328ae3701d92dbff9e3c85352cf5bf1b2da23739b9e3731ce6eacb1037e17
Deleted: sha256:5fbef17336dda4969357a50be691c93f16e8f6606f5939f72231d57aa0a1cd3a
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]# docker rmi 5fbef17336dd
Error response from daemon: No such image: 5fbef17336dd:latest
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED                  SIZE
nginx         latest    d261fd19cb63   Less than a second ago   152MB
ubuntu        latest    97bed23a3497   4 weeks ago              78.1MB
hello-world   latest    1b44b5a3e06a   2 months ago             10.1kB
[root@devopsvm01 dockerfile]#


8. Pull the image 

[root@devopsvm01 dockerfile]# docker pull mahekarthya/my-nginx-site:version-1
version-1: Pulling from mahekarthya/my-nginx-site
f637881d1138: Already exists
b8554c5f1ad0: Already exists
8e049f0fd151: Already exists
71a39d0d04b2: Already exists
e6918dcfd20d: Already exists
c4fca37af7b3: Already exists
bc1d7488b05e: Already exists
3e300a7cb18c: Already exists
4f4fb700ef54: Already exists
9610f25ad768: Already exists
7e4faa79bed1: Already exists
Digest: sha256:8ff328ae3701d92dbff9e3c85352cf5bf1b2da23739b9e3731ce6eacb1037e17
Status: Downloaded newer image for mahekarthya/my-nginx-site:version-1
docker.io/mahekarthya/my-nginx-site:version-1
[root@devopsvm01 dockerfile]#
[root@devopsvm01 dockerfile]# docker images
REPOSITORY                  TAG         IMAGE ID       CREATED                  SIZE
nginx                       latest      d261fd19cb63   Less than a second ago   152MB
mahekarthya/my-nginx-site   version-1   5fbef17336dd   54 minutes ago           48.3MB
ubuntu                      latest      97bed23a3497   4 weeks ago              78.1MB
hello-world                 latest      1b44b5a3e06a   2 months ago             10.1kB
[root@devopsvm01 dockerfile]#




No comments:

Post a Comment

Building a Safer PostgreSQL CI/CD Pipeline with GitHub Actions: Dev → PR Review → Test Promotion

In my previous post, we explored a simple push-to-main deployment strategy . While functional, that model is not considered an industry best...