Writing
DevOps0 min

How a server deployment actually works.

In this article, we take a look at how application deployment work using popular tools such as Docker, NginX, AWS EC2, AWS RD2 & more. This article is directed at junior software engineers who get lost in the world of high-level computing infrastructure. We will cover all the important basic concepts from threads to docker compose to backend microservices architecture.

The Problem

At the start of your software engineering journey, these concepts feel overwhelming especially if you started your programming journey with a general purpose programming language like JavaScript. Here we take a look at how simple everything actually is and what is hidden behind the intimidating terms like DevOps, Microservices, Cloud, Kernels and more. We will go from hardware all the way to deployment covering concepts only enough to give you a basic understanding.

The Core

So you have followed tutorials and ran `npm` commands to get your application running, you can see in the terminal that your application has started on a 'port' (usually 3000) and the command line says your application is up. You go to the browser and run localhost with the port and you can now see 'Hello World'. But what exactly goes on when you run the `npm run` command?

Just like every other program running on your machine, your running application is just a 'process'. A process is a isolated space of memory assigned to a program to do its tasks by the Operating System. One process is just a single instance of that program. Each instance is assigned at a minimum a single thread by the OS.

A thread is a sequence of instruction that gets executed on a core, one at a time. In the case of your application a single thread goes through your code line by line feeding these instructions to the CPU's core.

How does a CPU with for example 8 cores handles so many threads from so many programs at once? This is handled by the OS's Kernel which is basically the 'main' program of the OS. Internally it contains what is called a scheduler which picks up threads from many processes and executes them one after another on a core, even though it might look like your application is works continuously, internally core executes only 1 thread at a time, but it is so fast (thousands of threads in a second) that every process works without disruption.

The Communication Link

Your application is now up running as a process on your system with the operating system handling execution and its communication with your hardware, but how will other processes which might want to communicate with your application to get or send something communicate? This is where the concept of ports come in. Your system only has a single network adapter, to manage multiple processes which might want to listen for a network request it allows application to pick a number (0 - 65,535), this is treated as unique identifier for your application. Every time a request hits this identifier, the OS forwards this request to your application.

The Cloud

You have now your application running as a process, running on a port, listening for requests & your OS is helping execute any instructions that needs to be executed. But how does this work for real traffic & real users? Cloud in its simplest form is just computing infrastructure located at different parts of the planet allowing you to continously run your application on a device while paying the owner of that infrastructure to host it continously. You can do it on your own device as well but this requires infrastructure maintenance, scaling, IP configuration & hosting setup, things that the owner of the infrastructure promises to do for you, at a cost.

The DevOps part

Running your application in Amazon Web Services virtual machine (EC2) is similar to how your app runs in your own local machine, just now in a infrastructure hundreds to thousands of kilometers away from you. To maintain consistent uptime so your customers do not face any disturbance, typically we include a setup of web server (NginX), Docker & dividing your application up in microservices.

A microservice architecture exists primarily for applications providing services at scale. It divides application services into seperate parts such as payment service, authentication service, order or booking service. This ensures if one service is down, the others are not affected. So if your authentication is suffering issues, the order or booking service will continue to function normally.

To further bulletproof our application from facing issues, we use Docker. Docker is a platform that allow you to run your application in a container. A container is a process with its own memory isolated from other containers. Think of it as a lightweight virtual machine which contains its own processes, ports and uses the host operating system's kernel allowing it to maintain its lightweight nature. In Docker you run instance of your applications inside a container. For multiple instances you can create multiple containers. Which means for a single application you can get multiple containers up, so if a single one of your application instance fail we quickly shutdown that container and get another instance up as containers are lightweight and easy to get up. In case of our microservices, this means each microservice get multiple of their own instances running creating a web. This web can get complex to get up and running and this is where Docker Compose comes in. Docker Compose is a configuration file and toolset that lets you configure running your multiple instances of your application via a single command.

Web servers.

You have setup your application in a virtual machine and with docker multiple instances of your application are now up running. Now how will a request from clients hit your backend? This is where a web server comes in, we will take example of NginX which is just one of the many popular web servers out there.

Inside our Docker compose, we setup NginX which is a process listening on a port. This is the only port that gets exposed to incoming requests from different clients around the world. Your virtual machine on a cloud provider gets identified using static IP address which gets linked up to your domain. Every request on your domain gets routed to this IP which hits the request at the port nginx exposes. This by definition is called an API Gateway, which in this example we have configured nginx to be. Internally NginX provides features such as load balancing. It uses configurable algorithms to decide which service and which instance of that service should handle the incoming request.

Databases

If your application is a backend dealing with data storage, you would typically need a database. Databases are their own processes running separately as a unique instance. Databases generally come in two flavors. SQL databases like PostgreSQL or MySQL store data in structured tables with rows and columns. NoSQL databases like MongoDB store data in a more flexible format, closer to how JSON looks in your code.

Database server can be setup inside your virtual machines but to separate concerns and secure data integrity you can run it on a dedicated server. Cloud providers such as AWS provides services such as AWS RDS to run your database. You can also use external datastorage platforms for managing your data.

Running your database on a separate server from your application means your data stays safe even if your application server crashes or needs to be restarted. It also means you can scale your database and your application independently.

CI/CD Pipelines

One other thing worth mentioning is the concept of CI/CD pipelines which is something every developer deals with at earlier stages of their careers. These CI/CD pipelines are just a set of instructions that get linked up to your virtual machine, every push to your repository gets picked up by the VM and using the configured command it updates your code on the virtual machine and runs the configured commands. This removes the need to manually SSH into your server every time you make a change.

Conclusion

In this article, we discuss the flow of how applications work from a thread executing on a core to your web server receiving and forwarding requests. These concepts form the foundation that most production systems are built on, and understanding them puts you ahead of where most developers start.