#Engineering #Fintech Engineering

Publishing your first microservice

Olusola Akinsulere · March 21, 2024 · 8 min read

In this post, we would take the code the in the previous blog post and package with docker, then publish the image to a docker registry. Here you’d need an azure account to setup a private registry, at the end of this blog post, we’ll test that we can instantiate our published microservice on our development workstation (or personal computer)

What is a container?

A container, as its name suggests, serves as a repository for hosting microservices.

Definition: A container is a method for server virtualization. More precisely, it facilitates the virtualization of both the operating system and the hardware components. This enables the abstraction and virtualization of necessary resources for a microservice's operation. By partitioning a single computer's resources, containers allow multiple services to utilize these resources concurrently. This aspect of containers is instrumental in delivering cost-efficient solutions for running microservices in modern technology landscapes.

Containers and Virtual Machines (VMs) are often discussed in parallel due to their shared capability of isolating microservices, thereby preventing mutual interference. Prior to the advent of containers, virtual machines were the standard for service deployment. However, containers now offer an alternative that, in many contexts, proves to be more efficient. Nonetheless, the choice to deploy services within VMs remains viable and may be preferred under certain circumstances. A virtual machine contains a complete copy of its operating system that’s running on fully virtualized hardware. A container, on the other hand, virtualizes the operating system as well as the hardware.

What is an Image?

The term "image" is versatile and can be applied in various contexts. It might refer to a photograph or a digital snapshot, such as a hard drive's image for a virtual machine. However, within the scope of this discussion, our focus is on Docker images.

Definition: An image represents a bootable snapshot of a server, tailored in this instance to a microservice. This snapshot encompasses all necessary components for execution, including code, dependencies, and assets. For illustrative purposes, this chapter delves into creating an image of a video-streaming microservice.

A pivotal characteristic of images is their immutability; once an image is created, it cannot be altered. This immutability is crucial for maintaining the integrity of applied tests and security assessments, ensuring their continued validity and reliability.

Conceptually, an image serves as a dormant iteration of a microservice. It acts as a preserved state of the microservice, poised for activation into a container. This preparatory status allows for the seamless integration of the microservice into an application when required.

Installing Docker

To install Docker, go to the Docker website at https://docs.docker.com. Once there, find the download/install link and follow the instructions to install Docker for your platform. Once you have Docker installed, you can use the terminal to check that it’s OK by printing the version

docker —version

Creating a Dockerfile

To generate a Docker image, it is mandatory to craft a Dockerfile. This file acts as a blueprint for constructing an image via Docker, functioning akin to a script laden with directives for image assembly. The Dockerfile's contents systematically outline the microservice, incorporating its dependencies and supplementary assets. Each directive within the Dockerfile triggers the transfer of specific files into the image. Pertinently, the Dockerfile will include commands for importing our Node.js project as well as for installing npm dependencies necessary for the project's operation.

Let’s write the Dockerfile for the index.js in the previous blog post,

FROM node:20.12.1-alpine
WORKDIR /usr/src/app
RUN npm install —only=production
COPY ./src ./src
CMD npm start

In the code block above, the commencement of the Dockerfile is marked by the "FROM" directive. This line determines the foundational image from which our new image is derived. Specifying "node:20.12.1-alpine" as our base image implies that the resultant image will incorporate Node.js version 20.12.1. The term "alpine" here refers to a minimalistic variant that is further explained in an adjacent sidebar.

For projects utilizing languages or frameworks beyond JavaScript and Node.js, the selection of a base image diverges accordingly to suit the specific technological ecosystem in use.

The capability to select an appropriate base image is immensely beneficial. It opens the possibility of utilizing a wide array of public images available on Docker Hub, or alternatively, crafting a bespoke base image tailored to our requirements. This flexibility enhances the potential for leveraging existing resources, and throughout this book, various instances of employing third-party images will be showcased.

Furthermore, the code block features several instances of the "COPY" command. These instructions are responsible for transferring files such as "package.json," source code.

Another critical command is "RUN," which facilitates the execution of software within the image during its construction. This allows for modifications to the image, installation of dependencies, and execution of preliminary setup operations. In the provided example, the "RUN" command is utilized to install npm dependencies, thereby integrating them directly into the image. To package and run this docker file run the following command

docker build -t video-streaming —file Dockerfile .

- The `-t` flag enables us to assign a tag or name to our image, which is highly recommended for ease of reference. Without it, you'd be forced to identify your image by a long, cumbersome string of numbers—a far from ideal method.

- The `--file` argument is used to designate a specific Dockerfile for the build process. While this might seem redundant—given that the default expectation is a file named `Dockerfile`—its explicit mention here is for educational purposes. It becomes particularly relevant in subsequent blog posts, where we explore the strategy of maintaining separate Dockerfiles for development and production environments.

- The importance of the period (`.`) at the command's end cannot be overstated. This seemingly minor detail is critical as it instructs the build process to target the current directory. Consequently, all Dockerfile directives will interpret paths relative to this directory. Although changing this base directory allows for the Dockerfile to be situated away from the project's main assets, we do not utilize this capability at the moment.

Now we have to run the docker image, so we can see the live content of the image, to do this we run the following command

docker run -d -p 3000:3000 video-streaming

- The `-d` flag ensures that our container operates in detached mode, meaning it runs in the background without displaying logs in the current terminal. Without this option, the container would execute in the foreground, directly showing its output and occupying the terminal session.

- The `-p` option is crucial for port mapping, establishing a link between a port on the host operating system and a port within the container. Essentially, it acts as port forwarding, allowing network traffic directed to port 3000 on our development machine to be rerouted to port 3000 inside the container. This specific setup aligns with our microservice's configuration, which is programmed to listen on port 3000.

The `docker run` command, as illustrated in the diagram, activates our Docker image within a container, transforming it into an operational instance of our video-streaming microservice. The syntax `docker run -d -p 3000:3000 video-streaming` effectively:

- Executes the container in detached mode,

- Maps the container's port 3000 to the host's port 3000,

- Specifies the image to be instantiated as a container, in this case, "video-streaming," which is identified by the name assigned during the build process with the `-t` flag.

The choice of port 3000 is largely conventional, popular for its use in the development and testing of HTTP servers, though practically any other port number could serve this purpose.

- Finally, "video-streaming" denotes the name assigned to our image. This label facilitates the identification of the specific image to instantiate, especially relevant when multiple images are present. This naming directly ties back to the use of the `-t` option with `docker build`.

Creating a container registry

Follow this article by Microsoft to learn how to create a registry. After this has been done, we’d learn how to push our microservice to the registry, to do this we must first authenticate locally by using the command below

docker login <your-registry-url> —username <your-username> —password <your-password>

Before we can publish our image to the registry, we must tell Docker where the image is being pushed. We can do this by tagging the image with the URL of the registry with the docker tag as follows

docker tag video-streaming <your-registry-url>/<image-name>:<version>

We can now push our image to the registry, by using this command:

docker push <registry-url>/<image-name>:<version>

Congratulations on publishing your first image to your private registry! This milestone paves the way for deploying the image in a production setting. However, the deployment step awaits the construction of our Kubernetes cluster, a task we have slated for subsequent blog posts. In the interim, there are additional concepts to grasp and preparations to undertake.

It's essential to verify the functionality of our published image before proceeding further. This involves ensuring that we can successfully instantiate the image as a container directly from our cloud-based registry. Although our production environment is not yet in place, we can simulate a deployment scenario on our development workstation. This process is straightforward and mirrors the procedures covered in this post.

Executing a container from an image remains consistent, irrespective of the image's origin—be it locally constructed or sourced from a remote registry. We'll revisit the `docker run` command to facilitate this verification process, maintaining continuity with the techniques we've already explored.

To run the container directly from the registry, we can use this command:

docker run -d -p <host-port>:<container-port> <registry-url>/<image-name>:<version>

Navigate to your port on your browser, then take a look at how the video is being streamed from the container

**Conclusion

**If you don’t want to wait for the whole series to end to get the knowledge, you can buy my ebook on gumroad => Microservices . To encourage to keep up the pace with writing this blog post, you can buy me coffee with the button below

Buy me coffee

Originally published on substack

Enjoyed this?

Subscribe to get new essays in your inbox.