Learn How to Build and Push a Docker Image to a Container Registry
Tags: docker, tutorial, containers, devops
Published: 2023-03-18 07:59:37

[Docker](https://www.docker.com/) has become a popular tool in DevOps for the containerisation and deployment of applications. It provides a standardised way to package applications along with their dependencies and runtime environment into a container, which can be easily distributed and run on different environments. To make this process even more efficient, container registries have been introduced, which allow developers to store and manage their container images. In this tutorial, we will walk through the process of building a Docker image, configuring and pushing it to a container registry. By the end of this tutorial, you will have a better understanding of the containerisation process and be able to use container registries for efficient and scalable deployment of your Docker applications.

## What is a Docker Image?
A Docker image is a lightweight, standalone, and executable package that contains everything needed to run an application, including the application code, runtime, libraries, and system tools. Docker images are created using a Dockerfile, which is a script that specifies the steps to build the image.

To build a Docker image, you need to first create a Dockerfile that specifies the base image, any additional dependencies, and the commands to install and configure the application. Once the Dockerfile is created, you can use the "docker build" command to build the image.

The "docker build" command takes the path to the Dockerfile and uses it to build the image. The command first reads the Dockerfile, downloads any necessary dependencies, and creates an image from the specified configuration. The resulting image can then be used to run containers.

**Here are the basic steps to build a Docker image:**

![docker container creation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iswv9y6vz443epcsojts.jpeg)

1. Create a Dockerfile with the necessary configuration for your application.
2. Navigate to the directory containing the Dockerfile in your terminal.
3. Run the "docker build" command, specifying the path to the Dockerfile and a name for the image.
4. Wait for the build process to complete, which may take some time depending on the size of the application and the number of dependencies.
5. Verify that the image was built successfully by running the "docker images" command, which should list all the Docker images available on your system.

**_We will automate the above process using [Harness](https://app.harness.io/auth/#/signup/?module=ci&utm_source=internal&utm_medium=social&utm_campaign=devadvocacy&utm_content=pavan_docker_article&utm_term=get-started)_**, a continuous delivery tool. We just need to have the Dockerfile in the application repository (which we have in our sample repo).

Building a Docker image is an essential step in the containerisation process, as it allows developers to package their applications in a standardised and portable format that can be easily shared and deployed.

## Prerequisites
- Docker, preferably [Docker Desktop](https://docs.docker.com/desktop/install/mac-install/)
- Free [Harness CI](https://app.harness.io/auth/#/signup/?module=ci&utm_source=internal&utm_medium=social&utm_campaign=devadvocacy&utm_content=pavan_docker_article&utm_term=get-started) module to automate the process of building and pushing our Docker image
- A sample application to experiment. We have a [sample Node.js application](https://github.com/pavanbelagatti/Simple-Node-App.git) repository. Fork it and use it.
- A free [Docker Hub account](https://hub.docker.com/). We will be using DockerHub as our container registry to push our image. 

## Tutorial
I am assuming you have forked this [sample Node.js application](https://github.com/pavanbelagatti/Simple-Node-App.git).

The Dockerfile you see in the repo will be used to build and push our application as an image to the Docker Hub or any container registry of your choice.

```
FROM node:14-alpine AS development
ENV NODE_ENV development
# Add a work directory
WORKDIR /app
# Cache and Install dependencies
COPY package.json .
RUN npm install
# Copy app files
COPY . .
# Expose port
EXPOSE 3002
# Start the app
CMD [ "node", "app.js" ]
```

Next, sign in to the [Harness CI](https://app.harness.io/auth/#/signup/?module=ci&utm_source=internal&utm_medium=social&utm_campaign=devadvocacy&utm_content=pavan_docker_article&utm_term=get-started) module and create a project.
![Harness CI module](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ot00is9s13o4eeoa0okc.png)

Invite collaborators to your project if you wish.
![Invite collaborators](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8qfokgg7b9g34v0dy0f.png)

Select the Continuous Integration module.
![Continuous Integration module](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/smm7a6ylwz962agre7f0.png)

Let's get started with creating your first pipeline.
![first CI pipeline](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tgx0aj8gylz5zqqsovtl.png)

If this is your first time working with Harness, you need to authenticate with your source control management (wherever your application code/repo resides). Select the sample application repository. The one you forked, [this one](https://github.com/pavanbelagatti/Simple-Node-App.git).
![select repo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q9iape2oevyvnxtmeqch.png)

Since it is a Node.js application, we will select Node.js from the list
![nodejs application repo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7cx1grej90vsqq7alui6.png)

Above, you will see a default yaml for your application.
Click continue and you will land on the pipeline studio. (you may sometimes go to the yaml format, switch back to the visual format)
![pipeline studio](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mus82g642f36yb8r203v.png)

Under the execution tab, you will see 'Build Node App'. If you click on it, it is a step with the following details/settings.
![build node app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jqfnicnz9vzbxo8ld7ei.png)

Apply changes, save everything and run the pipeline. 
![run the pipeline](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7hd2g93iypkh0relh41u.png)

You should see a successful pipeline execution shown below.
![pipeline execution steps](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a6d0fshb7qaqiol20il2.png)

Now, let's edit our pipeline to extend the capability to push an image to the Docker registry.

Add a step and you will be presented with several options.
![step library](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qm9qaepcotzj93hsqrkq.png)

Select the one that says 'Build and Push an Image to Docker Registry'
![Build and Push an Image to Docker Registry](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6gf6wddmdeax8k0cd0pt.png)

We don't have a Docker connector; let's add it.
![docker connector](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1o8nk3ue21xqq31ei65l.png)

![adding connectr](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ojxghsabupkwlycbagjh.png)

A step-by-step guide will show you how to add it.
![docker registry details](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nwlcoctitktl06r19vst.png)

Add the DockerHub details as shown below. Your Docker Hub user name and add password as a secret.
![add details](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pwa7j7q7onagyda8pank.png)

Add your DockerHub username and password (add password as a secret)
![password as a secret](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6vwilf4g5eknsnmiklv.png)

Create a new secret and add your DockerHub password. 
![docker pass](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ufdwdlcggtt6cyq6udb1.png)

After you add your DockerHub details, this is how it looks.
![dockerhub all details](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z0f823sj8t8pnj7iqeut.png)

Next, you need to connect your DockerHub to the Harness provider. Select Harness Platform to connect here.
![harness platform](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3ccxwgeit9ipwz6e774.png)

Make sure the connection between the Harness and your DockerHub is successful.
![harness and docker connection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4a2eci9rj7hezd3hadlw.png)

Now you see your 'Build and Push an Image to Docker Registry' step with the added details.
![Build and Push an Image to Docker Registry step](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g57mcni61x4ru5rxkn0n.png)

In the above screenshot, `pavansa` is my DockerHub username and `samnode` is what I would like to name my image as. `meg` is the tag I am using. You choose what you want.

Apply changes, save and run the pipeline.
![run the pipeline easily](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3cwo8eg9ei7huwq71k7v.png)

You should see a successful pipeline execution.
![pipeline successful](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ltm3738zbbp0cl5d2nvv.png)

Let's verify if Harness has pushed our image to our DockerHub.
Let's go to DockerHub and see the repositories. You should see a new image pushed just a minute ago. 
![new image pushed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vyvcl3pkgl85qvhng3fd.png)

**_Congratulations!_** We have successfully built, tagged and pushed the image to the Docker registry. Similarly, from Harness, you have the option to push your image to any container registry of your choice, such as Amazon ECR, Harbor, RedHat Quay, JFrog Artifactory, Google container registry, GitHub container registry, etc. 

Now, whenever there is a new code push to the main branch, the build gets triggered and runs all the steps every time pushing a new image to the DockerHub. 

Take a look at my other tutorial, where I am showing a complete CI/CD workflow tutorial from scratch. 
{% embed https://dev.to/pavanbelagatti/learn-how-to-setup-a-cicd-pipeline-from-scratch-for-a-go-application-4m69 %}