Advanced

Node.js Microservices Deploying and Scaling

I want to go and start this course off by talking about some of the issues developers face when it comes to pushing code to production and how containerization can help us go and mitigate...

Table of Contents

  1. Course Overview
  1. Why Is Deploying Code to Production So Hard?
  1. Microservices for the Modern Age
  1. Docker and Kubernetes Basics
  1. Creating a Kubernetes Environment in AWS
  1. Module 6 — Containerizing Your Node.JS Microservice
  1. Module 7 — Deploying Your Node.JS Microservice to EKS
  1. Module 8 — Scaling Your Node.JS Microservice in EKS
  1. Summary

1. Course Overview

Course Overview

Hello, everyone. My name is Travis Thomsen, and welcome to my course, Node.js Microservices: Deploying and Scaling. I’m an independent course author at Pluralsight. I want to go and start this course off by talking about some of the issues developers face when it comes to pushing code to production and how containerization can help us go and mitigate some of those issues. Next, we’re going to go and take a Node.js Microservice and go and containerize it.

Now if you’re new to containerization, no worries, I’ll walk you through the process. Then we’re to go and set up an EKS environment in AWS and go and deploy our microservices to EKS using deployment manifests. And finally, we’ll go and scale up our microservice by going and using Kubernetes built‑in horizontal pod autoscaler. Some of the major topics that we’ll cover include how to containerize your microservice by creating a Docker image, creating an EKS cluster in AWS by using eksctl, how to scale up your microservice by using autoscaling in Kubernetes. By the end of this course, you’ll know how to containerize your microservice and deploy it to Kubernetes.

Before you begin this course, you should be familiar with Node.js and microservices. I hope you join me on this journey to learn containerization with the Node.js Microservices: Deploying and Scaling course, at Pluralsight..

2. Why Is Deploying Code to Production So Hard?

Version Check

This course was created using the following versions of Node.js, NPM, Docker, eksctl, and EKS..

Common Issues when Deploying Code to Production

Hello. I’m Travis Thomsen. In this video, we’re talking about some of the issues we, as developers, may face when it comes to pushing code to production. Now, I don’t know about you, but I’ve been in this industry for quite some time, and I’ve seen my fair share of issues when it comes to pushing code to prod. And it depends on the place you may have worked at, but the number one issue I’ve had, when it comes to getting code in production, has been doing manual deployments, and the reason why this one is such a big issue is that it really does open itself up to operator error, and trust me from experience, I can tell you, I’ve made my fair share of mistakes pushing code to production manually.

However, I’m sure you’re like, but Travis nobody does manual deploys anymore, right? Right? Well, that might not always be the case. Never underestimate an organization’s ability to not want to change. The other issue that you might potentially run into is dependency management. Sometimes your dependencies in development are all the way up to date and sometimes production is not and that can cause a whole host of headaches. Speaking of dependency issues, this leads into multiple environments.

It has been often my experience that development has always been up to date and prod not so much, and when you’re trying to debug an issue with your code, for some reason it’s not working in production, but it works fine in development, well, it’s because usually your environments tend to be a bit on the snowflake side, and they don’t always match up, and obviously, that is a huge issue. The fourth issue we’re going to be talking about is rollback procedures because some companies don’t exactly put a lot of forethought when it comes to rolling out code, and they don’t necessarily plan for failure, they only plan for success, and obviously, that has its own issues as well. These are the top four issues we’re going to be talking about in this video, and obviously, these four issues do not encompass everything, but they are the most common ones you could potentially run into in the wild. And trust me, I’ve encountered all four, not just at one organization, I have seen this multiple times at multiple different organizations. So let’s go and start talking about manual deployments and why they’re bad.

The first obvious thing is the fact that it’s being done manually. Manual deployments is a complete nightmare, and a lot of it is because it opens up a lot of room for operator error. Deploying code manually doesn’t always mean that you’re using FTP to copy files over, though, that is definitely a manual way of doing things. You could also be following a runbook and doing all the commands manually. It just means that there’s no automation involved during this process.

One of the places I worked at when we go to deploy code, we’re using SVN, and we would create a new directory and check the code out there and then change the SIM link and then change some configuration files. It was definitely not a good plan. Another company, we were using GI, and we would simply go and change the current branch over to the next release branch. And deploying code really should be something that doesn’t take more than 5, 10 minutes, and when you do things manually, it can literally take hours. The other issue when you deploy things manually, the more people that get involved, the more problems you’re probably going to have, and a lot of this comes down to communication, maybe somebody mentioning something in an email that you missed, or maybe they simply didn’t communicate things at all.

Sometimes when you add more people into the mix, it just adds more opportunity for failure. Typically, when you do things manually and there’s more people involved, it just becomes more complicated and convoluted and sometimes things just get missed. The other issue you might potentially run into with manual deployments is not using build artifacts. Having a build artifact really helps when it comes to rolling back your code to a previously working state, and the reason why is that everything is self‑contained and all you need to do is go and point your application back to the old build artifact. Another issue you may encounter is a lack of consistency when it comes to outcome.

When we go and deploy code, what we want is to have the job be boring. We want to make sure that whenever we go and push code to production, the outcome is always going to be the same, and when you do a manual deploy, there is no guarantee of consistent outcome. Why did the push to production fail this time? Did we follow all the steps? Maybe, maybe not, but when you do things manually, that’s not always going to be the case. Another thing I’ve experienced personally is a lack of a test plan once your code is in production. Sure, you might go and visit the web page that you’ve changed and test it out to make sure things work, but are you really testing out your code to make sure that things work right because there’s nothing worse than going home with a sense of satisfaction that your code is now in production and getting a call at 3:00 AM that things are broken.

Speaking of getting that call at 3:00 AM letting you know that everything is broken and it means that you have to go and roll everything back and you find out that there is absolutely no rollback plan. Like I mentioned that sometimes we focus more on success rather than failure, but planning for failure is always a good thing to do. Typically, when you’re doing things manually, you don’t necessarily have that rollback plan, and when you do, it typically means that plan is still manual, which means there’s still potential for error. Okay. Let’s talk about dependency management.

One of the biggest issues that you’re going to run into when it comes to managing dependencies is well, do your versions match or are they missing in your environments? If you’re rolling out a piece of new functionality and it’s dependent on a package that doesn’t exist, obviously, that’s going to be a problem. Then it comes down to the issue of whose responsibility is it to get that package onto the system? Is it you, the developer, or is it a member of IT who is managing the deployment? One of the things I personally experienced is that we were running Debian for our development environment, in production, we were running CentOS, so we weren’t even running the exact same flavor of Linux, and obviously, that caused its own issues, specifically when it came to the different version of packages that we were running.

You might be in a situation where version pending is not being used and it’s kind of a crapshoot on what version you’ll be getting in production versus the one that you’ve been using in dev. And of course, there’s also the issue of not going and removing stale dependencies. Even those unused dependencies cause issues if they remain in your production environment. The things that you need to consider is by not removing these old stale dependencies or deprecated ones, what kind of vulnerability am I opening the system to? Does it make this system easier to get hacked? Now, let’s talk about the issues of having multiple environments. The biggest issue is going to be that environments are snowflakes.

Rather than having something that is consistent across all of your environments, they differ. I mentioned the situation where we’re running Debian in development and CentOS in production, and obviously, that is a huge issue. Another thing you may encounter is the fact that your dev environment is always up to date, you’re running the latest packages, you know that your code is working against it and everything works great, but when you go to deploy things to production, production might be behind. Now, does this always guarantee failure? Not necessarily, but it doesn’t mean that other unforeseen issues won’t crop up. And then there’s your testing environment which is somewhere in between.

There’s been times where I’ve gone and deployed code, everything works just fine in development, but when I push it to prod and we discover that there is a segfault issue, and this issue is not being replicated in dev or testing, but only in prod, and it has to do with an older version of Apache and PHP that was being used, and when I told my manager that the easiest way of resolving the issue would be to go and upgrade Apache and PHP in prod, and then I was promptly told code around the issue.

The other issue that pops up when it comes to multiple environments is the attitude of well, it works fine on my machine. These are the words that no end user ever wants to hear you say, and trust me, if you’re ever in a situation where you utter those words, you will not make friends, it definitely doesn’t help when it comes to building relationships with your coworkers. And even if it is true that it works fine on your machine, the end user doesn’t care, they simply want the problem to go away. Now, we’ve already kind of talked about rollback procedures, but we’re going to talk about them in a little bit more detail. There has been plenty of times when code is being pushed to production that there really is no expectation of failure, and when that failure occurs, we’re simply left to our own devices on how to get things back into a working state.

In a lot of ways, it’s like that old adage, fail to plan, plan to fail. So not having a plan for failure is not going to make your deployment go any smoother, it’s just going to make things much, much worse. And then on top of that, even if you do have a plan, it’s a good possibility that it’s never been tested. It’s the same reason why schools have fire drills, it’s to make sure that if an emergency does happen, that you’re able to go and execute that plan efficiently with nobody getting hurt, specifically your developers. And then on top of that, now that things have been rolled back, how do we know that the application is functioning as it was intended to be? And just like with deploying things out, these steps are typically manual as well.

Okay. So we’re going to talk about some honorable mentions that doesn’t necessarily apply to what we’re, what we’re trying to solve here with containerization, but I figured I should probably bring them up. The other big issue that you might run into when it comes to deploying code to production is having to do database migrations, having to go and update the schema of your database and then migrating your data is not exactly an easy thing to do, and hopefully your DBA took a snapshot before doing so. Do you have any tools that you’re using for monitoring and logging? So if there is an issue, how are you getting those notifications out of the system? How are you handling vulnerabilities? Are you doing any kind of vulnerability scanning of packages or do you know that a certain package is out of date and needs to be patched because if not, it could go and open up your application to be hacked. And of course, there is release planning.

Release planning is good because you know exactly what is going out into production, but at the same time, if taken too far, it can open up a certain level of bureaucracy and that causes its own set of issues. And then there’s communication or the lack thereof. Communication within the organization is very important because you potentially could be introducing issues for another department by going and pushing code, especially if they’re not aware that those changes are coming. The other issue is you need to notify your customers as well because you could be introducing something that could greatly impact their business and that has its own ramifications. And my final piece of advice to you is never to deploy code on a Friday or Pearl Harbor Day for obvious reasons.

Okay. So now that we’ve talked about some of the issues with getting code in production and why it’s kind of a pain, let’s talk about some of the things that we can go and do to maybe make our lives a little bit easier..

Containerization Makes it Easier

Hello again. I’m Travis Thomsen, and in this lesson, we’re going to be talking about how we can use containerization to make our lives easier when it comes to deploying code to production. Now, the first thing I want to highlight is that containerization is not a silver bullet. It’s not going to solve every single problem. As a matter of fact, it might introduce new problems, but the goal is to ultimately make things easier on us when it comes to pushing code to prod.

So what issues does containerization solve for us? Well, just like previously, we were talking about manual deployments and this enables us to go and implement automation. Automated deployments are so much easier. Whether you’re using a pipeline or just using deployment scripts, the idea is to not do things manually. It can also solve the issues with dependency management because those dependencies are going to be baked into your container. It also solves the consistency problem among your environments, and the reason why is because your container is going to be your environment, whether it is development, testing, or production.

And then there is rollback and versioning. Because we’re creating a build artifact with our container, it allows us to go and roll back to a previous state without a whole lot of trouble, or at least that’s the idea. Let’s dig into automated deployments. As I previously mentioned, when you go and deploy your code, now you’re more likely to use something like scripts or a pipeline to go and deploy your code, and sometimes scripts and pipelines go hand‑in‑hand. Rather than going and just copying files to production or downloading them, you have a build artifact that you’re able to go and use, and this is going to help us in multiple ways.

The first off is because it’s fully encapsulated, and it makes things a lot easier when it comes to deploying code out. So when it comes to containerization, we’re going to be working with build artifacts, and that build artifact is going to be the image that we go and build. And because these images are going to be versioned, it allows us go and easily swap them out when we go and push our code to production, or I should say when we go and deploy out our new container. The other added benefit is that we’re using Infrastructure as Code. Whether you’re using a deployment manifest like with Kubernetes or you’re using Terraform or Puppet, you’re going to be using code that’s going to be checked into a repository just like the code for your application, and this code is going to declaratively define what your infrastructure looks like.

The ultimate goal when it comes to pushing code to prod is we want to make sure that everything we do is consistent and predictable. Like I said, deploying code to production really should be boring. The last thing I want to do is be up till 3:00 in the morning, troubleshooting why the deployment failed, and ultimately, if there is an issue with our deployment, we have an easy way of going and rolling back to a previous state because we’re just going to be swapping out the image that we’re going to be using. Dependency management. Everything is going to be prepackaged within our container, so we no longer have to worry about are the dependencies going to be up to date in dev, but not in production.

It doesn’t matter at that point because it’s all the same. Ultimately, this does not eliminate the need for version penning. However, all your dependencies are going to be encapsulated into your container image, therefore, it’s going to be consistent across all of your environments. If there is any issues, you’ll find out when you go and deploy it out to development first. The ultimate goal here is to make sure that we’re using the same version, whether it’s in dev, production, or testing, and by going and prepackaging everything, you’re going to be running the same version whether you like it or not.

Let’s talk about how this solves the environment problem. One of the many advantages of containerization is the fact that containers are portable, which means that you can run them on virtually any operating system. This allows a developer who is running a mac operating system to go and develop his code and containerize it, then go and deploy it to your testing environment which is running Docker on Ubuntu, and then finally release your container to production, which is running a managed Kubernetes environment on Azure. The idea behind it is that the underlying operating system that is going to go and run the container is really irrelevant, so when your environment is no longer the issue, it means you no longer have the snowflake problem because your build artifact is ultimately going to be the environment where your code is being executed. So this means that your dev, testing, and production environments are all going to be the same because it’s using the exact same container.

The only thing that is going to be different is what that container is actually running on. And when we have a consistent environment across dev, testing, and production, and even your own development machine, it really does get rid of the excuse that well, it works fine on my machine. We know that if it works fine on your machine, it’s going to work fine pretty much everywhere else. And finally, rolling back is not as difficult as it was previously, and the reason why is because we have the ability to use container orchestration tools. These orchestration tools could be something like Kubernetes or even Docker Compose, and because we’re using build artifacts and Infrastructure as Code, we know exactly what our environment is going to look like, and because we’re using build artifacts and Infrastructure as Code, it makes the process of rolling back, not only repeatable, but consistent.

We’re going to have a consistent outcome, which is getting our application working again, and we are much less likely to get a critical failure when it comes to rolling back to a previous state. And the reason why we’re able to go and roll back so easily is because what we’re doing is we’re swapping out our build artifact. Rather than using the one that is failing, we can use the one from the previous deployment that we know is good. And on top of that, some of this can be achieved by using the orchestration tools that I talked about previously. One of the advantages of using Kubernetes is that it allows you to roll back to a previous ReplicaSet, but I’m kind of getting ahead of myself, and we’ll be talking about this more in the future.

And like I said, I just want to reiterate the fact that containerization is not a silver bullet. The idea behind it is to make your life easier, and by extension, everyone else’s. I’m Travis Thomsen, and I’ll see you in the next one..

3. Microservices for the Modern Age

Making Your Microservice Cloud Native

Hello again. I’m Travis Thomsen. In this video, we’re talking about how we can go and make our microservice cloud native. Now, it’s a good possibility that you could have your microservice already be cloud native and didn’t even know it. Now, a lot of these principles what I’m taking from is the Twelve‑factor app, and if you want to learn more about the Twelve‑factor app, you can go to 12factor.net for more details.

Now, I’m not going to be listing all the 12 factors, but we’re going to be talking about the ones that are really relevant to what we’re trying to do with containerization of our microservices. So what exactly is the twelve‑factor app? It’s a methodology for going and building out Software as a Service application. Now, it may not be Software as a Service that you’re doing, but your app is going to function like it to an extent. So the first thing that we want to make sure that we do is that we use declarative formats when it comes to setting up automation. Ultimately, we’re going to be going and deploying our application out to a modern cloud platform, be it Azure, Google, or AWS, or even your own on‑prem Kubernetes cluster.

We want to make sure that it doesn’t matter what platform that we’re going and deploying our code to, and we want to make sure that we minimize any divergencies between our production and development environment. If you’re practicing continuous delivery or continuous deployment, minimizing these changes is very, very important. Okay. So this is where we start talking about some of the 12 factors. The first one is codebase.

One codebase to track revision control, many deployments. Dependencies, explicitly declare and isolate dependencies. Config, store config and the environment. Backing services, treat backing services as attached resources. Build, release, run, strictly separate the build and run stages.

Port binding, expose port services via port binding. Competition, scale out via process model. Disposability, maximize robustness with fast startup and graceful shutdowns. And finally, we have dev/prod parity, keep development, staging, production as similar as possible. Now let’s go and take a look at these factors in more detail.

Factor one is codebase. A twelve‑factor app is always going to be tracked in a version control system. Whether you’re using Git or subversion, your code is under source control. There is always going to be a one‑to‑one relationship between your codebase and your repo. Your codebase is not living in multiple repos because if it is, that means it’s going to be a distributed system, and if you are using a distributed system like microservices, they’re going to follow the exact same 12 factors as any other application.

And we want to make sure that if we have any shared code that that shared code is being handled through libraries. Factor two, dependencies. When it comes to packages, we want to make sure that we are not relying on system‑wide packages, but instead, we are using a distributed system like CPM for Perl, or RubyGems, or even NPM for Node.js. And when we go and declare our dependencies, we want to make sure we use something like a manifest file like a package.json file for Node.js or gems file for Ruby. Factor number three, config.

Now, the configuration is what is going to be different between each of the individual environments. These could be API keys or passwords to connect to the database or the URL for the database because these are the things that are going to be different between each of the environments that you’re working with, and we don’t necessarily want to store them in code like a config file, we want to make sure that we store them in the environment. It doesn’t mean you can’t use a config file, but that config file should be referencing those environment variables, and the best way of determining whether you succeeded at this or not is can your app be open source without going and compromising any of the credentials that you’re using? If the answer is no, then you’re not storing your configs in the environment. Now, I’ve already kind of spoiled this one. We want to make sure that we’re going and storing all of our config data as environment variables rather than in the file itself.

Factor number four, backing services. Backing services are services that your app is going to be working with. These are things like your database, or Memcached, or Redis, or RabbitMQ, and the main thing we want to make sure is that there is going to be no distinction between if we’re using these things locally or if we’re using a third‑party service, they should all function exactly the same using just different configurations information. And the reason why you want to treat your backing services as attached resources is let’s say you switch providers, maybe you’re tired of using Azure and you switch over to Digital Ocean. Well, Digital Ocean also provides a managed MongoDB service and all you need to do is just update the configured information once you’ve migrated over to go and use that database.

And we want to make sure that we go and store that configuration information using environment variables. Factor number five, build, release, run. When it comes to releasing our code to production, we basically have three stages that we’re going to be dealing with. The first one is going to be the build stage, and this stage is where we go and create our build artifact, sometimes it’s just referred to as the build, and then we go through the process of releasing the build to production, and this is where we’re go and pull in our build artifact along with our configuration and information, and ultimately, we get to the final stage where our app is actually running in that production environment.

Factor number seven, port binding. Now, when we go and run our application in production, we want to make sure that it is being bound to a port, and we’re not using a third‑party web server to do this for us. And again, this is going to be very much determined by the language that you’re using. Node.js, we have the ability to use the express package and handle this for us. And again, we could do very similar things with Ruby and Python.

The idea behind it is that we want our application to be fully self‑contained, and that if we are going to be using a web server, it is going to be a package, and therefore, a dependency that we’re able to go and use. Factor number eight, concurrency. When it comes to concurrency, we want to make sure that we scale out using the process model. In a twelve‑factor app, processes are treated as first class citizens. This has been heavily influenced on the UNIX process model for running service daemons.

The process for the Twelve‑factor app should never be daemonized or write out a PID file. Instead, we want to make sure that we’re relying on how the operating system is managing processes. Factor number nine, availability. We want to make sure that our processes are disposable and that they go and start up, you know, pretty quickly, and we want to make sure that we have mechanisms in place that if it does take our code a bit of time to go and start up, that is not being accessed right away, and this is where things like readiness checks and health checks come in. And then we want to make sure that we have the ability to go and gracefully shut down our application either through a SIGTERM, and if you’re using like a web application, it’s no longer listening on the specified port that it’s bound to.

Now, the final factor we’re going to be talking about is number 10, which is dev/prod parity. There has been substantial gaps between development and production, and it manifests in one of three ways. The first one is the time gap. When a developer goes and works on code and it’s ready to be released, sometimes it can take a bit of time to get it released in production, and a lot of this depends on the release cycle of the organization you’re working at, sometimes it could be a week, maybe it’s a month, maybe longer. The idea is that once our code is ready to go to production, it gets released as soon as possible, and this is where continuous delivery and continuous development come in.

The second gap is the personnel gap, the developers go and write the code and somebody from either IT or potentially DevOps are the ones that are responsible for going and releasing it. The way we can go and reduce the personnel gap is by making sure that developers are involved in the process. And the third gap that is defined is the tools gap. This gap is the stack differences between your development environment and your production environment. Sure, maybe you’re developing on macOS and you’re running SQLite in NGINX, but in production, you’re using something completely different.

The way we go and minimize the tools gap is by making sure that what we’re running in development is exactly what we’re going to be running in production. The Twelve‑factor app really is designed for continuous development. This way, when the code is ready, it’s able to be shipped as quickly as possible, and the way we do that is making sure that we have parity between our environments. And ultimately, this is what we’re working up towards. By going and using containerization for our microservices, we’re able to go and ensure that we have our dev/prod parity.

I am Travis Thomsen, and I’ll see you in the next one..

Microservice Overview

Hello again. I’m Travis Thomsen, and in this video, we’re going to be taking a look at the architecture of the microservices that we’re going to be working with throughout this course. Now, the application that we’re going to be working with is an inventory management system for beverages, and it consists primarily of two microservices. You have the inventory microservice where the point of sale system is able to go and manage the inventory that they have on stock and then a restocking microservice that when they go and run out of a beverage, they’re able to go and place an order. Now because we’re not actually shipping real product, we’re going to be simulating everything through API calls.

Now, the first thing that we need to note is that there is no web interface for this system, so we’re using Postman to go and post a request to the API gateway, and depending on the request that we’re making, the API gateway is going to go and forward our request either to the inventory microservice or to the restocking microservice. Now let’s go and take a look at a few of the requests that we’ll be working with. The first one is going to be the ability to go and get the inventory from our system. Simply, we were just making a get to API inventory and that is going to go and route over to the inventory microservice and go and retrieve things from Mongo DB, returning it back to Postman. The inventory microservice consists of two components, the APIs and then the inventory messaging system.

The inventory messaging system is going to get information from RabbitMQ about a particular product, such as when there’s a reorder and we need to update the stock, and that will be used to go and update our beverage. Now for the restock microservice, there’s two calls we’re primarily going to be working with. The first one is going and placing a reorder, and that is opposed to API restock. The API gateway is going to go and route the information to the restocking service and then go and place that order into the MongoDB database. Now, this does not update the stock on the inventory, and we have another call that is going to go and simulate that.

We’re going to go and make a put to API restock and then the restock ID and then update stock. Now there’s a bunch of things that would happen in between placing an order like going and boxing up the product and shipping it out. Obviously, we can’t do any of that, so instead, we’re just going to go and simulate that process. So when we use Postman to make that call, the API gateway is going to send the message over to the restocking service. The restocking service is going to go and get that order from MongoDB, and then it’s going to go and tell RabbitMQ that it’s time to go and restock that beverage.

RabbitMQ is then going to go and communicate with the inventory messaging system and update the stock in MongoDB. So now that we have an idea of ​​how our microservices are going to work, let’s go and take a look at the code..

Demo: Is Your Microservice Cloud Native

Hello again. I’m Travis Thomsen, and in this demo, we’re going to start taking a look at our microservices that we’re going to be using throughout this course, and the main thing we want to do is check and see that what we actually have is cloud native. So what exactly are we going to be doing here? So I want to go and take a look at each of our microservices, like I said, and just have an idea of ​​what we’re going to be working with throughout the course, and does it stack up to what we want with our Twelve‑Factor app? Does it meet the requirements to truly be cloud native? Okay. So let’s go and jump into it. Now, before we start looking at the code, I want to talk about how I went and developed everything.

I use two tools to simulate what we’ve been talking about over the last two modules. The first one is Docker desktop and this allows me to run Kubernetes locally without having to go and run minikube. The second thing is Scaffold. Scaffold allows me to go and containerize my application and then deploy it to Docker Desktop using Kubernetes using a deployment manifest file, and the nice thing about it is I’m able to go and roll out the entire stack with a single command and then tear it down when I break out of it. So ultimately, you’re able to go and write your code, develop it locally, and simulate how you would go and push it either to a testing or production environment using the exact same methods that we’re going to be developing throughout this course.

It’s something I wish I could talk about in more detail, but it really is out of the scope of this course, but it is a tool that you should be aware of. So if you have not worked with Scaffold before, I highly recommend it, it’s really simple, and it’s a good way of being able to go and containerize your microservice locally before and going and testing it like in a dev environment and a testing environment, and ultimately, rolling into production. So let’s go and take a look at the first one which is going to be the API gateway. Now, I want to go and pull up the package.json file first, and the reason why is because we were talking about making sure that we have our dependencies in a manifest file, and that’s what we’re doing here with the package.json file. And as you can see, each of the individual dependencies have been pinned to a version, and again, this is done by default when you use an npm install.

So if I come back over here and I go over to src, I’m going to go and pull up my configuration file first. So according to our Twelve‑Factor app, we want to make sure that we don’t store things in config, and that’s exactly what we’re doing here. We are using environment variables, and yes, we are using a config file and that’s perfectly fine, but we’re not really storing anything locally in this file, it’s just a mechanism to get our environment variables into our application, and the only thing I’m really setting by default is going to be the port, everything else I’m just setting a blank value to. And the other two things I’m setting in here is going to be the endpoints for my microservices, and as we progress through this course and we start building out our deployment manifest, I have the ability to go and set these environment variables in the deployment manifest itself. Okay.

So let’s go and look at index.ts. This is basically the heart of our application, and the main thing that we’re looking for here is am I using port binding, and well, as you can see here, the answer is yes, and again, because we are using an environment variable to go and set our port number, and we are using express which is going to act as our built‑in web server, so when it comes to is our app actually cloud native, let’s go and take a look at the 12 factors.

Is everything running in a single codebase? The answer is yes, dependencies. Are they isolated? Yes, we are using a dependency manifest, and we’re not linking on system packages. The config, are we using environment variables? Yes, we are. Backing services, are we treating them as attached resources? Yes, we are. Build, release, run.

I’m not going to say that this is more difficult to answer, but the answer again is yes, and if I go back over to the package.json file, you can see that that is essentially what we’re doing here. We go and take a look at the package.json file. We’re using tsc to go and build our application, and this is going to be part of the Docker image build portion. So yes, we are separating out our build stage from our release and run. So what about the rest of the 12 factors? Well, it’s a little bit more difficult to answer because we really haven’t gotten there yet.

We, we have most of it. We were using port binding, that’s another yes. You know, concurrency, we really can’t answer yet. Disposability. Yeah, we can because when we are no longer going and using the microservice, it’s going to go and terminate its connection, and again, these are things that are largely going to be handled by Kubernetes when we go and deploy our app out, and we go and take a look at our other applications, the answers are going to be the same.

So let’s go and take a look at the inventory system next. Again, we have a package.json file here. We have all our dependencies in it, and of course, these dependencies are versioned, and when we take a look at src, we do have our configuration file here, and as you can see, we have our port again, but this time we have an environment variable for our database, and this is our connection string to MongoDB, and there is no sensitive information in this configuration file. And if I go and take a look at index.ts, you can see we’re doing the exact same thing. We do have port binding as well.

So does it adhere to the Twelve‑Factor app? Well, again, we have a single codebase for our application. The dependencies are isolated, we’re not using system packages. Our configuration is being stored in the environment. And again, we’re treating our backing services as attached resources, and it does follow the build, release, run model. So the answer is yes, our application is cloud native.

So let’s go and take a look at the next microservice. Alright, and that is going to be our inventory messaging. We come down here and take a look at package.json. We’re using tsc to go and compile our TypeScript code down to JavaScript, and again, this is going to be handled by the Docker file, and when it comes to our dependencies, they are being declared within our package.json file as well. If I come back over here to src and look at the config, you can see that we have several different environment variables that we’re going to be using here.

And again, there is no sensitive information that is being captured. We have our database connection string, we have the URL for our RabbitMQ server along with the username and password and then the default queue that we’ll be using. I believe I end up overriding this. Now, let’s take a look at the index.ts file. Now, I want to point out that the inventory messaging is, I’m not going to say a special case, it’s not publicly accessible like our other two microservices.

This is mainly just to be the interface between the inventory microservice and RabbitMQ. Now, I could have bundled this with the inventory microservice, but I decided against it. So I guess the question is why do I have the port in the config file? And that is just really an oversight on my part, and I forgot to remove it. Okay. So let’s go and take a look at our final microservice which is going to be the restock app, and you probably guessed it, it follows the exact same patterns as we’ve seen before.

Again, we’re using tsc to go and compile the code, which means that we are extracting our build step‑out, and again, this is largely going to be handled by Docker. And then we have our dependencies and they’re pinned and they are in the manifest file just like everything else that we’ve previously seen. Let’s go take a look at the src and the config file. We have an environment variable for our database connection string, and again, we are treating it as an attached resource. We also have the URL for our RabbitMQ service, the username and password for it, and then the default queue, so everything again checks out here.

And when I go and take a look at the index.ts file, we can see that, again, we are going in using a port, so our app is going and binding to a port as well. So the question is, is this app cloud native, and I’m just going to go with yes based off of the previous factors that we’ve talked about. Alright, so now that we’re done talking about issues with deploying to production and how we can make our microservices cloud native, let’s start talking about Docker and Kubernetes in the next module. I’m Travis Thomsen, and I’ll see you in the next one..

4. Docker and Kubernetes Basics

Understanding Images

Hello again! I’m Travis Thomsen, and in this lesson, we’re going to start our journey of going and containerizing our microservice. But before we can do that, we need to understand what Docker images are, since we’re going to be using them to go into play out our microservice. So, what exactly is a Docker image? The high‑level explanation of what a Docker image is is that it is nothing more than just a blueprint of the libraries and dependencies that you’re going to need to run your application in a container. Now, if you’re familiar with the concept of virtualization, you can think of a Docker image as just being like a snapshot because you’re going to use that snapshot to go and create something from it. So when we go and build out our Docker image, it is going to go and contain instructions on how to go and build a container.

These instructions include things like what the base image is going to be, what steps we need to go through to go and make sure that our application is going to go and run on the container, and finally, we also have how the application is going to be executed when that container goes and starts up. When the image is constructed, it is going to consist of multiple layers, and I do have a visual representation that we’ll get to in a moment of demonstrating what these multiple layers look like. In a lot of ways, I like to view Docker images as being a large layer cake because that’s exactly what they are. They are comprised of multiple layers that are built on top of one another. And the reason why this is done is to help speed up the build time, as well as keep the file size small.

Also, Docker images are considered to be build time constructs. And the reason why is because, well, they are created at build time. In a lot of ways when we containerize an application, there’s a lot in common with microservices. We want to make sure that what this is going to do is it’s going to solve a single problem. When we go and create a container, we want to make sure that it has their code and dependencies and really nothing more than that.

We’re not going to be running a database in it. It’s just going to be there to go and execute our code, and when we go and create that image, it’s going to have our code and all the necessary dependencies that that code relies on. So, in this instance, we’re going to be creating a Node.js application. So this is going to go and include our source code for that application, along with our node modules. The other thing it’s going to have is environment variables.

And these are very important because we want to make sure that when we go and build out our application and we build our container that we’re able to go and pass in environment variables to tell our application how it goes and either communicates with other services, or the fact that our code is actually running in production because there might be some different functionality that is enabled when we have our code in production.

The other thing is we want to make sure that it has all the libraries and runtimes that are necessary to go and run our application. In this instance, we are going to be working with Node.js, so we need to make sure that we have the Node.js binary so our code is able to go and be executed. So in my previous example, I said that in a lot of ways images are like layer cakes because they’re comprised of multiple layers. The main thing to understand is that each of these layers are going to be immutable, which means that once the image is built, they’re never going to change. However, any changes that are going to be made when we go and create our container are going to be made to the container layer, and this layer is going to go and sit at the very top of all the other layers.

So, for example, let’s say that we have a web server container and you have the ability to go and upload images. Well, those images are going to be uploaded to that container layer because that is the read/write layer. Everything else below that is going to be completely unaffected. Now, each layer in our image represents a single instruction. The very first layer, which is going to be the base layer, is typically the base image that your image is going to be built on top of.

And then any layers on top of that are going to represent different instructions from copying your code over to go and installing packages to setting up the entry point for the container. The other most important thing about understanding image layers is that each layer is going to be a delta from the previous one, which means it’s not going to contain any of the information from the previous layer. It’s just going to have its own changes from that instruction and that is it. Okay, so let’s talk about Dockerfiles. Now, the way we go and build Docker images is that we use something called a Dockerfile, and in that Dockerfile is going to consist of the set of instructions of how that container is going to be run.

So as you can see here at the very top is that we have our FROM. What we’re telling Docker is that Node.js 21‑alpine is going to be the base image that we’re going to go and build on top of. Next up, we have the RUN instruction, which is going to be used to go and execute something locally on the container where we’re going and setting up the image so we can do a yum update. Next, we have another instruction that is going to go and set the working directory, and we’re setting it to /app. And this is where our code is going to be copied to and that any commands that we run without specifying another directory are going to be executed in that working directory.

We also have the COPY instruction, which allows us to go and copy information from our local system over to the image container where we’re going and building it. After that, we have another RUN instruction, which is going to tell the container to go and install the necessary packages for the application using npm install. After that, we have another instruction that is going to go and expose a port, and this is going to be port 3000. So when we go and use this image to create a container, we’re going to have port 3000 exposed by default. And then finally, we have the command that is going to be run to start our application.

There’s two ways of going and starting a container. We have CMD, which stands for command, and we also have entry point. For the most part, they do exactly the same thing. That’s the over‑simplified explanation of it. But entry point is a little bit more sophisticated.

So when you use an entry point, it’s going to go and configure the container to run as an executable. Now, another thing that is worth noting is that an entry point cannot be overwritten at runtime. On the other hand, CMD sets the command that will be executed when the container is running. It’s also worth noting that this command can be overwritten at runtime. In this example, the command that will be executed when the container goes and starts running is npm start.

Now, as I previously stated, each instruction represents a single layer. So here we have a diagram that represents that. At the very bottom, we have the FROM, which is going to go and get our base image, and then each instruction after that represents another layer. Finally, until we get to the very top, which is going to be the command that goes to run the container when it starts up. Now, all these layers, as I previously mentioned, are going to be read‑only because images are immutable and they do not change once they’ve been built.

That’s all I have for this video. I’m Travis Thomsen, and I’ll see you in the next one!.

Understanding Containers

Hello, again! I’m Travis Thomsen. Now that we have an idea of ​​what Docker images are, it’s time to talk about containers. So, what exactly is a container? Well, the super high‑level explanation is that it is nothing more than a virtualized runtime environment for your application. For me, the way I like to explain the difference between an image and a container and essentially what they are is that if you’re familiar with object‑oriented programming, your image is going to be your class, and the container is going to be an instance of that class. Now, it is very important to understand that containers are ephemeral, which means that they essentially are temporary.

They are not meant to live for extended periods of time. That way for whatever reason, if your container crashes, what you need to do is go and spin up a new one. Now, because of the ephemeral nature of containers, any information that is written to that container is going to be lost when a new one is spun up in its place. So just be aware that containers do not by default have any kind of persistent storage, and that’s something we’ll address later on in this course. The other thing that’s really nice about containers is that they are standardized, which means that when you go and run the same container in your dead environment, in your staging environment, and in your production environment, they’re going to function exactly the same.

Containers are meant to be lightweight. What that means is that we want to keep them as small as possible, only having the necessary things that we need to go and run our application. Like I mentioned, we have our code, its dependencies, any kind of libraries and runtimes that are needed, as well as environment variables. The other thing that’s great about containers is that they’re secure. Because we don’t run containers as route, if it becomes compromised, it is abstracted away from the base operating system that our containers are running on.

So if they do become compromised, we simply just go and kill the container and spin up a new one. Let’s go and take a look at how containerization works. At the very bottom, we have our infrastructure. Just like with Amazon, we have base‑level infrastructure that everything is going to go and run on top of, and it’s not any different here when it comes to containerization. What sits on top of the infrastructure is going to be our operating system, just like your PC that you’re probably watching this on or on your phone, all these have operating systems which basically allow us to go and interface with the hardware.

On top of the operating system is going to go and sit our container engine, and this is going to be something just like Docker. And finally, the container engine allows us to go and run and operate containers. Because a container is nothing more than an instance of a container image, it also has layers. Where images are build time constructs, containers are runtime constructs; they come into existence during runtime. Now, the big difference between images and containers is that a container is going to go and have a writeable layer.

So anytime we write something to that container, again, we’re not changing any of the immutable layers, we’re going and writing to that writeable layer. So anytime we go and make a change, those changes are going to be stored in that read/write layer, and that read/write layer is what really represents what a container is. When we go and destroy our container, all we’re doing is just deleting that writeable layer. Now, in the previous video, you’ve already seen this diagram. We have our image layers, and we know that these layers are read‑only.

But when we go and create our container, as you can see, we have our read/write layer at the very top, and this is considered to be the container layer. And like I mentioned on the previous slide, any changes that are going to be made to that container are going to be written to that read/write layer, and that the image itself is completely unchanged. So building on top of what we just talked about, as you can see, we have our Docker image down at the very bottom, and then we have three containers that are being built off of it. And again, these are nothing more than just instances of that image because those containers are really just represented by that read/write layer. And again, once we go and terminate our container, all we’re doing is deleting that read/write layer, and the container image is completely unaffected.

Okay, that’s all I have for this lesson. I’m Travis Thomsen, and I’ll see you in the next one!.

Kubernetes Overview

Hello again, I’m Travis Thomsen. Now that we have a better idea of ​​what containerization is, let’s start talking about Kubernetes. So, what exactly is Kubernetes? The oversimplified explanation of what Kubernetes is, is that it’s nothing more than just an open source platform that allows you to go and manage containerized workloads and their services. And the way this is done is by using declarative configuration files and the automation to go and manage all that. It’s also worth noting that Kubernetes can be abbreviated as K8s.

And where this is derived from is that you have the K and the s, and the 8 comes from the 8 letters in between those two. This way, if you hear somebody referring to Kubernetes as K8s, you know exactly what they’re talking about. Kubernetes is also Greek for helmsman, which is why we have the nautical theme. Now, let’s talk about some of the key features of Kubernetes. Kubernetes is able to go and manage the deployment of containers using container orchestration.

It goes and abstracts the underlying infrastructure, allowing you to go and focus on defining and running your application. Another important feature of Kubernetes is the ability to go and manage the entire cluster. It doesn’t matter if you’re using EKS or if you’re running Kubernetes on bare metal, Kubernetes is deployed out into a series of nodes. You have your worker nodes, and then you have your management node, which is responsible for orchestrating everything out to the individual worker nodes. Now, the management node contains the control plane, and that control plane is able to go and communicate with the worker nodes which runs their own software, which allows you to go and execute the desired task on that specific node, whether that is going and deploying out a pod or going and setting up a service to go and make that pod publicly accessible.

Now, I’m sure all of you are familiar with infrastructure as code. What this allows us to do is declare what we want in a configuration file. And Kubernetes is no different. Kubernetes uses a YAML file known as a manifest to go and describe the resources we’re going to go and deploy out. By default, pods run in isolation, which means that they are not publicly accessible, either internally or externally.

So we use services to go in as service discovery. So, for example, let’s say that we have an application that uses a MongoDB database. By default, that Mongo database is not accessible. But by using a service, our application is now able to go and connect to it using the service name. And we’ll talk about this in more detail once we get to services.

Now, another great feature Kubernetes is the ability to go and work with load balancing. When we go and deploy out our microservice to EKS, we will actually be using the load balancing services that are offered by AWS. Now, one of the most advanced features that Kubernetes has to offer is the ability to perform rolling updates, as well as rollbacks. When we go and execute a deployment, all the pods that are pre‑existing will not be terminated until all the new ones have been spun up and are online and ready to take their place. When we start working with deployments, one of the things that we can do is roll back to a previous deployment.

So, for example, let’s say we deploy out a new version of our application and there is a massive critical failure for whatever reason, we can roll back to the previous working state. Now, I have to preface this with that we’d never actually want to leave a deployment in a rollback state. We want to make sure that we go and deploy out a new working version. In reality, a rollback is just a quick fix to get the application back into a working state. Kubernetes is also self‑healing.

Now, as I previously mentioned, containers are meant to be ephemeral, which means that they are temporary. And for whatever reason, if there is a failure, they’re going to go and die off. Kubernetes has mechanisms in place that if for whatever reason a container does die, one will be spun up to go and replace it. Another thing that we’re able to do is go and define the resource limits on the CPU and memory that our containers are going to be able to go and consume. What this allows for is the effective management of our nodes.

Now, I’d like to think that microservices and Kubernetes really do kind of go hand‑in‑hand. Because we’re going to be running multiple microservices, we want them to run in their own individual pod. Now, if we were to do this and run them on EC2 instances, they can get pretty pricey, especially if you have a large number of microservices. Now, what Kubernetes allows us to do is run our microservices spread across the individual nodes. This means that if we have a four‑node cluster, we have four nodes to go and spin up individual pods, which are basically the wrappers for containers, and have them to point out to the various nodes.

So if we have, let’s say, 10 microservices, we can go and deploy out all 10 of those microservices onto our cluster, and therefore, we’re not going to be spinning up individual EC2 instances for each of the microservices. It gets even worse if we want to go and autoscale and have more for when it comes to site reliability and making sure that we have access to all of our microservices because redundancy is important. This allows us to go and run multiple copies of that microservice across all of our nodes within our cluster. So the four basic components we’re going to be talking about throughout this course is going to be pods, services, replica sets, and deployments, and each of these components are going to have their own videos where I dive into them in more detail. Okay, that’s all I have for this video.

Coming up next, we’re going to dive a little bit deeper into Kubernetes where we’re going to start talking about pods. I’m Travis Thomsen, and I’ll see you in the next one!.

Kubernetes Pods

Hello again! I’m Travis Thomsen. And now that we have an understanding of what Kubernetes is, let’s start talking about probably one of the most important pieces in Kubernetes pods. So, what exactly is a pod? Well, it is the smallest deployable unit in Kubernetes. Now, I want to point out that pods themselves are not actually containers. What they are is they are a wrapper for a container or a group of containers.

Most of the time when you go in to plant a pod, it is simply going to be a single container, but there may be instances where you need to have a helper container, and that is going to exist within that pod. And the reason why they’re called pods, in a lot of ways they function like either a pod of whales or a pea pod, especially when you have multiple containers that are contained within a single pod. Much like containers, pods are ephemeral. Once they die, they do not come back unless you have a means of recreating them. And we’ll talk more about that when we start talking about replica sets.

When it comes to the contents of a pod, they’re always going to be co‑located together. This means when a pod is created, all the containers will be scheduled together on the same node. Speaking of scheduling, when a pod is created, all those containers in that pod will be scheduled at the same time. Pods use shared resources. This means that containers within the pod are going to share the same namespace and network which allows them to go and communicate using localhost.

Containers within a pod can also share storage, such as volumes, and can synchronize data. When we take a look at the diagram, we can see an example of the shared resources. Within our pod, we have two containers, we have a microservice, and then a helper container. And as you can see, both of them are going to access the same volume. Okay, so let’s now talk about how we can go and start creating pods.

Now, in the presentation, I included a link to this website, and this is all about pod definitions. In the previous video, I mentioned that Kubernetes is declarative, and we’re going to be using YAML files to go and describe how we want our pod to be set up. And this page here includes all the definitions we need to go and do that. Now, when we go and create our definitions, we’re going to go and save it into a YAML file. For this example, we’re just going to call it pod.yml.

And the way we go and begin our declaration is by specifying the version of the API. So here we have apiVersion, which is going to be v1. We also need to include the kind of resource we’re going to be working with. So, for this instance, we have kind and Pod. Note that Pod is capitalized.

And then we’re going to go and include some metadata about our pod. The first one is going to be name, and name can literally be anything you want it to be. So, for this example, we have a name for our pod, which is going to be static‑web. And below that, we’re going to go and set up a label. Now, labels are largely going to be arbitrary, and they are key‑value pairs.

However, labels are very important for when we start working with services. So for here we have a label that is up as app:web‑server. So, app is our key, and web‑server is our value. We also need to include a spec for the pod, and that spec is going to consist of containers. We can have a list of containers, but in this instance, we only have one, and this one is going to be called web.

So we’re supplying the name of web, and below that, we need to tell it what image we’re going to be using, which is going to be nginx, and then, finally, any ports that need to be exposed. And again, ports is going to contain a list of ports. And again, the name is arbitrary, we’re going to call it web, and we have two things that we’re going to be including here. We have the containerPort, which in this instance is going to be port 80 because that’s what nginx runs on by default, and then the protocol, which is going to be TCP. Now, I can literally go and just take this code right here, put it into a YAML document and execute it, and it will go and create a pod.

So let’s go and do that. We’ve been working with theory for a couple of videos now. It’s time to get our hands a bit dirty. So what are we going to be doing? We’re going to go and create a pod YAML file, very much based off of what I just showed you. And then we’re going to learn some of the Kubernetes commands that we use to go and manage pods.

This includes creating, as well as deleting, listing, and even inspecting. So we’re going to go and deploy out our first pod, and it’s going to be using the example which I just displayed. Okay, so let’s go ahead and get into it. Now, following along with this demo is optional, and in order to do that, you’re going to need something that is running Kubernetes. Now, there are several options you have available to you.

One of them is minikube, but I think that Docker Desktop is a lot easier. However, I do want to point out that if you are working for an organization, you might need to purchase just a license for Docker Desktop. Now, Docker Desktop does have Kubernetes built into it by default. If I come over here to the gear and click on that, Kubernetes right over here. And all you need to do is go and click on that, and that will go and enable the version that we have here, which is 1.28.2.

Now, in order for you to go and follow along, there’s a few other things you’re probably going to need. You’re going to need an IDE, I’m using Visual Studio Code, and you’re going to need something like Cygwin or Git Bash. And what this allows you to do is to go and simulate a Linux‑like environment. Now, if you’re working on a Linux system or on a Mac, you pretty much already have this by default. So this is more specific to what we’re going to need for Windows users, Okay, so the first thing we need to do is come over here, and we’re going to go and create a new file, and I’m going to call it pod.yml.

I’m going to go and minimize this over here so we have more real estate. And as I mentioned, the first thing we need to do is start off by specifying the API version. And that is going to be api, and then Version. We separate things by using a colon because that’s what we do with YAML. And that version is going to be v1.

Next up, we have a kind, and a kind is always going to be capitalized, and the kind we’re dealing with here is going to be Pod. Next up, we have our metadata. Because YAML is tab‑delimited, I need to go and tab into spaces, or I can hit tab, but I quite frankly just prefer to use spaces, and we’re going to go and supply a name for our pod. And I’m going to call it static‑web. Now, also, I’m going to be including a label.

So we go and define our label, and, again, we come in two spaces, and our label is an arbitrary key‑value pair. I’m going to call my key app, and my value is going to be web‑server. Okay, and you come all the way back in, and now we’re going to go and define out our spec. The spec basically just tells you what is going to be within our pod. And the first thing up is that we have containers.

And we’ll be supplying a list of containers, even though we’re only using one. So we need to go and name that container. I’m going to go and call it web. And again, because we’re using a list, I need to come in two spaces and we’re going to supply the image, which is going to be nginx. And finally, we supply our ports.

And again, this is a list. So we come in two spaces, begin with the dash, I’m going to go and name this web port. So we have more things that we need to include, so I need to come in two spaces, and we need to supply our container port. Again, Port is capitalized. Anytime there’s a second word, it’s always going to be capitalized.

And that port is going to be port 80, and this is the port that is being exposed by the nginx image. Finally, to finish things off, we have our protocol, which is going to be TCP. Again, that needs to be capitalized. Now, I’m going to go and save my file. I’m going to come back over here, and I’m going to go and select Terminal, New Terminal window.

Now I have PowerShell by default. What I want is Bash. And if I come over here and click this drop‑down, you can see that I have Git Bash right here as an option. I want to go and maximize this. Whenever we go and interact with our Kubernetes cluster, we’re going to be using kubectl.

This is basically the master command. So, kubectl. And just to get familiar things, I’m going to type get all. So, typically we have get pod or get service. Get everything literally is going to list everything that is available to you.

And as you can see right now, the only thing that we have is a service, and this is basically the Kubernetes API that we’re going to be interacting with using kubectl. All right. So now we want to go and deploy out our pod, and the way we do this is by executing kubectl, and then apply. And because we’re going to be using a file, we use the ‑f flag, and we specify the file we’re going to be working with, which is going to be pod.yml. And if I hit Enter, oh okay, I see what the issue is, I have a typo.

So if I come back over here and go and minimize this, it’s supposed to be labels, not label. Go and Save, and let’s go and try this again. Okay, now we have a working pod. Let me go clear my screen real quick. And if I execute a kubectl get, this time I’m going to do pod, or you can do po, which is basically short for pod, it’s going to go and list just the pods.

And as you can see, we have our static‑web, and it is running, and we have 1/1. So this pod consists of 1 container, which is currently running. And then we have 0 restarts, which means that the container is not either in a failed state and it’s trying to go and restart. Sometimes if you go and deploy an application out and you’re trying to connect to a database and it’s having issues, the container is going to go and continue to restart until it’s able to go and establish a connection with that database. All right.

So now that we have a working pod, let’s go and delete it. And the way we do this is by executing a kubectl, and then I’m going to type delete. And, again, I can go and supply my file by using the ‑f flag, and then the name of the file, which is pod.yml. And if I do a kubectl get all, you can see that our pod is no longer running and it has been deleted. Okay, let’s go and deploy out our pod again.

So, kubectl apply ‑f and then pod, and we’re going to go and work with some other commands. If we want to go and just list our pods, we can type kubectl get pod, or we could just do po, which is the shorthand for it. You can see that we’re only getting back a list of our pods. Now, if I want to get more information about my pod, what I can do is kubectl and then describe pod, or I can just do po, and then the name of the pod, which is static‑web. This command is particularly useful if you’re having issues creating a pod because we are getting a list of events back, and you can see that everything was created and started up fine.

Now, if there was an issue, odds are you’ll find that issue here, or we can go and inspect the logs on the container itself. Okay, and the way we get our log files is that we do a kubectl and then logs, and then the name of the pod, which is going to be static‑web. And as you can see, we can get logs back. Now, this is also helpful when we’re having issues with our pod, but say that it’s having problems either creating and it keeps failing and we see them being restarted over and over, we can come here and find out what is wrong with our pod to go and help us diagnose what the issue is. Okay, that’s all I have for this video.

Coming up next, we’re going to be talking about services. I’m Travis Thomsen, and I’ll see you in the next one!.

Code Examples

# Exemple de définition de Pod Kubernetes
apiVersion: v1
kind: Pod
metadata:
  name: web-server
  labels:
    app: web-server
spec:
  containers:
    - name: web-server
      image: nginx:latest
      ports:
        - containerPort: 80

Kubernetes Service

Hello again! I’m Travis Thomsen. And in this video, we’re going to start working with Kubernetes services. So, what exactly do Kubernetes services do? Previously when we went and deployed out our pod, it is operating in isolation, which means that it’s not really publicly accessible. So we go and use services to go and make those pods available on the network. When we go and create a service, what we’re doing is we’re defining a logical endpoint, and typically that logical endpoint is going to be your pod.

And this is also going to establish all the policies that make that endpoint publicly accessible. Now, as I previously mentioned, service discovery is another key component of Kubernetes, and the way we do this is through services. What this means is that it allows us to use the service name to go and access the pod. Again, going back to our Node.js application that has a MongoDB back end, when we go and create that MongoDB pod, we’re going to go and create a service that is going to make it available on the network. And by using the name of the service, our Node.js application is going to be able to go and access the MongoDB database.

So let’s go and take a look at an example. So I have this diagram on how pods and services work together. Over on the right‑hand side, we have our established pod, and then we’re going to go and set up a service, which is going to go and expose this pod onto the network. Now, the first thing we have to do is make sure that we have a label for our pod. And again, this is a key‑value pair that is arbitrary, and we’re just going to call app:web‑server.

And then we have to have a corresponding selector for the service that also has app:web‑server. So by using the selector, it’s going to go and find a matching pod with the label of app:web‑server, and it’s going to go and route traffic to it, making it exposed onto the network. I’ll also be including a link to services in the presentation so you can go and check this out. And this page, again, is going to go and define everything that is necessary to go and describe what a service looks like. Now, when we go and describe our service, it’s going to start off very similar to how we did with our pod.

We’re going to be creating another YAML file. And again, we’re going to be supplying the API version, which is going to be v1. We also need to supply our kind, which is going to be service. And again, the service has to be capitalized. We also have metadata.

We’re going to go and name our service. So when we do service discovery, it’s going to be available using web‑service. And again, we have a spec for our service. Now we have multiple things here. The first one is going to be our selector, and remember, our selector has to go and match the label that we created for the pod.

We also need to go and define our ports. The first one, we have a protocol of TCP and a port of 80. So this is going to go and match up with what we have exposed on our pod. We also need to include a type, which is going to be NodePort. Now, if we don’t go and declare a type, now if we don’t supply a type, one will be selected for us by default, and that’s going to be cluster IP.

So now let’s do a side‑by‑side comparison of a service and a pod and how these work. Now, I mentioned that we need to have a selector, and our selector is going to be app:web‑server. And that is going to go and match up with our label here, which is app:web‑server. Okay, so now that we know a little bit more about pods and services, let’s go and put things into practice. So we’re going to start working with Kubernetes services.

And again, much like before, we’re going to be creating a YAML file for our service, and then we’re going to go and deploy it and make our pod publicly accessible. So let’s go and jump into it. So I’m going to go and start things off by going and creating a new file. I’m going to call it service.yml. I’m going to go and close this so we have more room.

Just like before, we’re going to start off with apiVersion, and the apiVersion is going to be v1. We need to supply our kind, which is going to be a service with a capital S, and below that, we’re going to go and set up our metadata. And here we’re going to go and define the name of our service. And again, because we’re working with YAML, we need to go and indent. So, name, and I’m going to call this my‑service, and that’s all we need for that.

Now we’re going to go and define our spec. And again, we need to go and indent. And the first thing we’re going to do is we’re going to go and declare our selector. And again, I need to go and indent. And remember, our selector needs to go and match the label that we define for our pod, which is going to be app, and then web‑server.

After our selector, we’re going to go and define our ports. So, ports. And again, we are dealing with a list, so we need to go and indent and use a hyphen. And I’m going to go and define the protocol, which is going to be TCP. And TCP does need to be capitalized.

I need to go and indent because we’re working with a list. I’m going to go and define our port, which is going to be port 80. And remember, this is the port that is exposed on the pod itself. And now another thing that I did omit. Now, one thing I did omit on the slide is that we can go and define a target port.

And typically, the target port is going to match up with exactly what we just defined here because target port by default uses the port number. It’s the reason why I omitted it. And now we need to go and define our type, which is going to be NodePort. And by default, if I don’t supply a type, it’s going to default to cluster IP, which means that our service is only going to be accessible within the cluster. All right, now I’m going to go and open up my terminal again.

I’m going to close out PowerShell, and I want to make sure that we’re using Bash. Now, if you’re working with multiple YAML files, you don’t need to go and deploy them out individually. What we can do is do kubectl apply, and then again, ‑f, and we can just supply a period rather than the individual filename. So if I do that, you can see that we have our pod and service being executed at the same time. And if I do a kubectl get all, you should see that we now have our pod running.

We have 1/1, which means it’s good. And then we have my‑service, which has the type of NodePort. Again, it has the internal IP for the cluster. And then we have a port 80, which is being mapped over to 32758. So if I go to localhost and I access that port, we should get our web‑server.

So let’s go and try that out. If I come over here, I enter a localhost and the port number of 32758, we get the default nginx webpage. Now much like our pods, if we just want to get a listing of our services, we can do kubectl get and then service, and you can see it goes and returns back a list of our services. I can also go and describe one of my services. So I can do kubectl describe service, and then the name of that service.

So we’ll just do my‑service. And you can see we have all the information coming back about that particular service. We have the namespace, any labels, we have our selector, which is app:web‑server. You can see the type, which is NodePort. And then things like the IP addresses, the load balancers, we have an ingress for a localhost.

You can see that our port is 80 TCP. With the target port, again, like I mentioned with target port, it uses port by default if we don’t specify one, and then we have the NodePort, which is 32758. And much like our pod, we can go and delete it by executing a kubectl delete, and then we supply the name of the file, which is going to be service. Now, alternatively, what I can do is I can do delete service and then supply the name of the service, which is my‑service. And if I go and type kubectl get service, you can see that, helps if I spell it right, you can see that our service is now deleted.

Okay, that about wraps things up. Coming up next, we’re going to go and start working with replica sets. I’m Travis Thomsen, and I’ll see you in the next one!.

Code Examples

# Exemple de Service Kubernetes
apiVersion: v1
kind: Service
metadata:
  name: web-server-svc
spec:
  selector:
    app: web-server
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

Kubernetes ReplicaSets

Hello again! I’m Travis Thomsen. Now that we’ve been working with services and pods, it’s time to talk about ReplicaSets. So in a nutshell, we already know that pods are ephemeral and that when they die off, they die off permanently. And so we need a way to make sure that when a pod dies that they come back. This is basically what gives the self‑healing element to Kubernetes.

And the way we do that is using these ReplicaSets. So they are a guarantee that we have availability on our pod. What this allows us to do is we can define a number of pods that we want running, and that ReplicaSet will go and enforce that number of pods. The other added benefit of using a ReplicaSet is that we have the ability to go and scale up to meet demand. This can be achieved one of several ways.

One is that we just simply increase the number of replicas within our ReplicaSet, or we can use something like an autoscaling group to tell the ReplicaSet what our min and max is going to be. And we’ll be talking about that more in a future video. So let’s go and take a look at a quick diagram of what a ReplicaSet looks like. Over on the right‑hand side, we have two pods, and these pods, again, we have a label of app:web‑server. Now, our ReplicaSet is also going to have a selector with a key‑value pair, and that key‑value pair needs to match the label that has been defined for the pod.

When we go and run a pod in a ReplicaSet, it doesn’t change the way it interacts with our service. Because that service also has a selector and a key‑value pair, the service is still able to go and route traffic to those pods. I’ll also be including a link to this page, which has everything you need to know about how to go and describe a ReplicaSet. As you can see, our YAML code is growing. This time when we go and declare our API version, it’s not going to be simply just v1.

It needs to be apps/v1. The kind, we’re going to be defining a ReplicaSet. And again, the R and the S are capitalized. And we also have our metadata. We’re going to go and define the name of our ReplicaSet.

This one’s going to be called a replica‑static‑web. And then we also have a label of app: web‑server. Coming down over to spec, we’re going to go and spin up three replicas. This is going to be the number of pods that is going to be created by our ReplicaSet. And we also have our selector and matching label.

Now, this is very important. This is going to go and match up with the pod declaration. Now with a ReplicaSet, the way we do our pod declaration is that we go and create a template. And in the template, it’s going to contain all the things that we’ve already seen in a pod definition. This is going to go and include our metadata, along with our pod spec.

And just like with our service, the selector match label has to have the same key‑value pair that is defined under labels in the metadata for the pod spec. Now the template spec is going to be the exact same thing that we’ve already seen before with our pod definition. It contains the exact same information. Okay, now that we’ve gone and covered the basics, let’s go and jump into a demo. Using the information that I presented to you in the previous slide, we’re going to go and create a ReplicaSet manifest.

If our old pod still exists, we’re going to go and delete it, and then we’re going to go and replace it with the brand‑new ReplicaSet. And the ReplicaSet is going to go and create the number of pods that we define under replicas. Okay, let’s go and jump into it. We’re going to go and start things off by going and creating a new file, and I’m going to call it replicaset and .yml. As always, we need to go and define our apiVersion.

This time, our apiVersion is going to be apps/v1. We’re going to go and supply a kind, which is going to be ReplicaSet. Again, remember both the R and the S are going to be capitalized in ReplicaSet. And now we’re going to go and supply our metadata. And again, because we’re working with YAML, we need to go and indent.

So I’m going to go and name my ReplicaSet, and I’m going to call it replica‑static‑web. And then I’m going to go and supply a label as well. So, labels. And again, we need to go and indent. I’m going to call this app: web‑server.

Now it’s time to go and supply our spec. We want to make sure that a ReplicaSet is having a minimum of three pods running at all times. So I’m going to say replicas, and we’re going to supply 3. Now, we also have to go and supply selector, and this selector requires a match label. So we’re going to say match and label.

Actually, it’s plural, labels. We’re going to supply app and web‑server. And that’s going to be app: web‑server. Now that we’ve gone and supplied our selector, we’re going to go and define our template for our ReplicaSet. So I need to make sure that I supply a template.

Again, I need to go and indent. Now I need to go and define the metadata, which is going to be working with our selector and matchLabel, indent, and then labels. And you go and indent again, and then app: web‑server. Now, this template also has a spec. So when you go and define containers, I’m going to go and indent, and we’re going to be supplying a list of containers.

And remember, we’re only supplying one. And this is going to be called web. We also need to go and supply the image that we’re using, which is going to be nginx, and our ports. Again, our ports is going to be a list, so we need to indent and use a hyphen. We’re going to go and name this web port.

Also we need to indent again, and we need a supplier container port, which is going to be containerPort, again, with a capital P, and this is going to be port 80. And finally, we need to supply the protocol, which is going to be TCP. And that is it. We can go and save. So just like before, I’m going to come over here and just get that out of the way, and come over here to Terminal.

I’m going to open up a New Terminal. I’m going to go and close that PowerShell because I just want Bash. Now, first things first, I want to see what I have running so I can do a kubectl get all. Okay, you see that we have our static pod running. I’m going to go ahead and kill that.

So I’m going to execute a kubectl delete, and po, ​​and then the name of the pod, which is static‑web. And if I run kubectl get all, you can see that we only have the Kubernetes service running, which is fine. Now we’re ready to go and deploy out our ReplicaSet. So, execute a kubectl apply ‑f, and then the name of the file, which is ReplicaSet. Okay, as you can see, I have an error.

It looks like I misspelled protocol. So I just come back over to my file, go and minimize this real quick, come back down, and correct that spelling error. Okay, let’s go and try that again. Work this time. So if I do a kubectl, I can do a get replicaset, you can see that we have our ReplicaSet running.

It shows that we have a desired 3, we have 3 running currently and that we have 3 ready. So let’s do a kubectl, and then get pod. You can see that we have our pods running. And again, we don’t have a service for this, so these pods are not publicly exposed. So I can execute kubectl and apply ‑f, and then I can go and supply the file for service.

Okay, so let’s do a kubectl get all. We can see that everything is running. So again, we have our pods, we have 3 of them running, we have our service, which is my‑service, and then we also have our ReplicaSet. Okay, so if you note here that we have a port of 31062, and if I go and open that up into a browser, you can see that our pods are pulling up. And if I go and pull it up into a browser using localhost in the port, you can see that we do have the default nginx page pulling up, which means that our pods are publicly accessible using the service.

Just to show you how ReplicaSets work, I can go and kill off a pod and it will go and recreate it. So I can do a kubectl delete po, and then I’m going to go and grab this pod right here, paste it in, and if I do a get all real quick, you can see we already have another one running in its place. So that is pretty freaking fast. As you can see, this is the one that just got created because it has an age of 2 seconds. Just like everything else, we can go and describe a ReplicaSet.

But first I want to go and list it. So kubectl and then get replicaset. Okay, there is the name of our ReplicaSet. So now we can do a kubectl and then describe, and then we also need to supply replicaset, and then the name of the replicaset. So I’m just going to go and copy this right here.

And you can see we have all the information that we need for our ReplicaSet here. So if I go and scroll up a little bit, you can see that we have the name of the ReplicaSet, it’s in the default namespace, we have a selector of app: web‑server, and we also have labels of app: web‑server. We also have our replicas; we have 3 current, 3 desired. And we have the pod status, which is 3 running. When we come back over here, we have our pod template.

If I scroll down, we have a label of app: web‑server. And then we have our containers. The container is web. It’s using the image of nginx. We have port 80, and we also have if there was any kind of environment variables that will be listed here.

No mounts, no volumes. And of course, we have the events on our ReplicaSet. Now to go and list my ReplicaSets again, and let’s go and talk about deletion. Again, just like anything else, we can do a kubectl delete and then supply replicaset and then the name of the ReplicaSet, but of course, there is the easier way of handling it, which is going to give you kubectl and then delete, and then we can use ‑f, and then the name of the file, which is going to be ReplicaSet. Now, just for good measure, I’m going to go and delete the service as well.

So I’m going to go and back this out, and then service.yml, and everything is deleted. So if I do a kubectl and then get all, you can see everything has been cleared out. Okay, that is all I have for ReplicaSets. Coming up next, we’re going to be talking about deployments. I’m Travis Thomsen, and I will see you in the next one!.

Code Examples

# Exemple de ReplicaSet Kubernetes
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: web-server-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-server
  template:
    metadata:
      labels:
        app: web-server
    spec:
      containers:
        - name: web-server
          image: nginx:latest
          ports:
            - containerPort: 80

Kubernetes Deployments

Hello again! I’m Travis Thomsen. So far, everything we’ve been doing has been building up to this point, and that is working with deployments. When it comes to a deployment, this is really the apex of what we want to do with our microservice. Now, the reason why we want to use a deployment rather than just a ReplicaSet is that we have additional set of features at our disposal when it comes to using a deployment. In a nutshell, when we use a deployment, it goes and deploys out a ReplicaSet.

So I’m sure you’re asking yourself if they essentially do the same thing, why use a deployment over a ReplicaSet? So the issue is when we go and use a ReplicaSet and we deploy it out, it’s going to go and overwrite the previous ReplicaSet. When we use deployment, it’s going to go and perform a rolling update, which means that it’s not going to replace the previous ReplicaSet until all of the pods of the new ReplicaSet have been deployed out and are online. And this is done to go and minimize any kind of downtime for our deployment. Now, if there’s changes to our pod template, the deployment is going to go and maintain a history of our ReplicaSets. For this to go and work right, it means you’re going to have to have a tagging strategy for your Docker images just like you have a tagging strategy for your code.

And by default, a deployment will keep a history of 10 ReplicaSets. And again, this is all dependent on the pod template changing. So make sure to go and keep that in mind. By going and maintaining this history, it allows us to go and roll back a deployment if it goes and fails. Now, there’s a few caveats that need to be brought up when it comes to rolling back.

You never want to leave your deployment in a rollback state. Because this is infrastructure as code, we want to make sure that our deployment matches what we have in our deployment manifest. So we never want to leave it in that kind of ambiguous state. Let’s go and take a look at a diagram here. So now we have a deployment, which is going to go and encapsulate our ReplicaSet.

And of course, that ReplicaSet is going to go and encapsulate our pods. And just like before, we have a service, and it has a selector of web‑server, and that is going to go and match with the labels that we’ve defined for our pod. So when it comes to accessing our pod using a service, nothing has changed between a deployment and a ReplicaSet. Now, I want you to pay very close attention to the YAML that is here on the screen. As you can see, this is what a ReplicaSet looks like, and here is what a deployment looks like.

Did you see what changed? Well, the only thing that changed here is the kind. We are no longer using a ReplicaSet. We are now using a deployment. And I also changed the name from replica‑static‑web to depl‑static‑web. But that’s it.

Everything else is literally the same. Okay, so let’s go and move on to the demo portion of this video. We are now ready to start working with Kubernetes deployments. So what we’re going to do is we’re going to go and create a new deployment file, and we’re going to go and copy the contents of our ReplicaSet and paste it in and just make the necessary changes. And then we’re going to go and deploy it out.

Okay, so let’s go and jump into it. So just like before, we’re going to go and create a new file. We’re going to call it deployment.yml. And rather than type everything out, I’m going to cheat. I’m just going to go and grab everything from the ReplicaSet.

Oops, that’s the wrong thing. Back over here, and just paste it in. And what I’m going to do is I’m just going to go and change ReplicaSet to Deployment. And then I’m going to go and change the name, and I’m going to call this depl. All right, everything should work at this point.

Come back over here, and I’m going to open up my terminal. I’m going to close out PowerShell. And now, just like before, we’re going to go and execute a kubectl and apply ‑f, and supply our deployment.yml file. And now we can do a kubectl get all. Now you can see that we have something new here, which is our deployment.

So much like before, we have three pods. We have our ReplicaSet right here, which is showing. We have a desired 3/3. And the same thing here under our Deployment, we have 3 ready, 3 up‑to‑date, and 3 available. I can also do a kubectl get deployment, which will go and list all of our deployments.

And if we want to get more information on the deployment, we can do a kubectl describe deployment, and then the name of the deployment. Okay, we have everything that we need. So if I go and I scroll up here, you can see that we have the name of the deployment, the namespace which it exists in, which is default, we have our label here, any kind of annotation, we have our selector, ReplicaSets, and we also have our pod template, which has our containers, which is web, the image, which is nginx, and the port of port 80. And of course, now at the very bottom, we have the any kind of events that have taken place. If we want to go and delete our deployment, we just do a kubectl delete, and then I can just use ‑f, and then the file we want to go and delete from, which is going to be our deployment.yml file.

So if I do a kubectl get all, you can see everything is gone again. Okay, so now that we have the basics of containerization and Kubernetes under our belt, it’s time for us to start working with EKS. In the next module, we’re going to go and start deploying out our EKS environment. I’m Travis Thomsen, and I’ll see you in the next one!.

Code Examples

# Exemple de Deployment Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server-depl
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-server
  template:
    metadata:
      labels:
        app: web-server
    spec:
      containers:
        - name: web-server
          image: nginx:latest
          ports:
            - containerPort: 80

5. Creating a Kubernetes Environment in AWS

Demo: Setup Account Prerequisites

Hello again! I’m Travis Thomsen. And in this lesson, we’re going to start our journey to go and create our EKS cluster. But before we can go and do that, we need to get some prerequisites out of the way first. Now, the first thing we want to do is go and create a user group. Now, this user group is going to contain all the necessary IAM roles, along with the necessary policies, so we can go and use a command-line tool to go and deploy out EKS.

Next, we’re going to be going and creating a user account, and this user account is what we’re going to be using to go and create our EKS cluster. Now, we will not be using this to go and log in. What we really need is an access key which will allow us to go and access AWS remotely. Okay, let’s go ahead and get started. Now, the tool we’ll be using to go and deploy out EKS is eksctl.

And if we come over here to Usage and scroll down, we want to look at the IAM policies. So we have Minimum IAM policies, go and click on that. If you are actually running this in a production environment, I highly recommend that you use the policies that they use here. But because we’re using this as a demo, the policies I’m going to be creating is going to be a bit on the lax side. But I want to make sure I highlight that before I go in and create this, that this is not going to be production‑ready.

In order to make it production‑ready, go and use the minimal IAM policies. So let’s go and jump over to AWS. Now, the first thing I want to do is I’m going to go and search for IAM. I’m going to go and select that. I’m going to come over to User groups, and I’m going to go and click Create group.

Now I want to go and name this group. I’m going to call it eks‑group. I’m going to come down here, and I have some policies I’m going to go and search for. The first one I’m going to search for is amazonec2full. Come over here and click on that.

We can go clear that out. The next one’s going to be fully accessible. Click on that. And finally, the last one is going to be awscloudformations, and it should be this first one here. Let me scroll this over.

CloudFormationsFullAccess. Go and select that, come down and click Create group. Okay, so now that we have our EKS group, there is a policy I need to go and create. So I’m going to come over here to Permissions, and we’re going to go and Add permissions. Create inline policy.

And come over here and click on JSON because we’re going to go and add some stuff here. Now, I already have this policy pre‑staged. I’m just going to go and delete this and paste it in, but let’s go and talk about it. Now, what this policy allows us to do is to go and install EKS remotely using the EKS CLI tool. Under the Effect, we have Allowed.

The action is eks, and the resource is *. Now we have another action, and we’re going to be setting two things. We have ssm:GetParameter and ssm:GetParameters. We also have a resource of * and an Effect of Allow. So, coupled with the other IAM policies that I previously added, this will allow us to go and use the EKS CLI tool without getting any kind of errors.

Now, I’m sure you want to have access to that JSON file that I pasted in, so if you come over to rivethead42/node.js‑microservices node Js dash microservices‑deploying‑scaling, just come over to Section05 here, and then click on S05L01. And in here, we’re going to have everything that we’re going to be using. So if you just scroll down, here’s the JSON right here. Now, one of the things you’re probably going to see is that we have an error here. This is actually correct.

Now, I’m not sure why this is displaying as an error. It’s most likely an issue with the AWS interface, but rest assured you, I did test everything, and it does work fine. Now, I’m going to scroll down to the bottom and I’m going to click Next. Now, all we have to do is go and name our policy. I’m going to go and name it eks‑policy.

Let’s go and scroll down and save it. All right, everything is good. Okay, now that we have our group created and our policy added, we can go and create our user. So come over here to Users, I’m going to come up here and click Create user, and we’re going to call this eks‑user, and click Next. We’re going to go and add our group, which is going to be eks‑group.

Go and check that. And come over here and click on Next. We’re going to scroll down. We can go and add tag if we want. I’m just going to go ahead and bypass that.

And then come down here and click on Create user. Okay, now that we have our eks‑user, I’m going to come over here and click on it. Come over here to Security credentials. I’m going to go and scroll down. I’m going to go and add an access key.

So click on Create access key. I need to go and scroll up, and we’re going to be using this for command‑line interface, so go and select that. And then scroll down, and we need to go and check this box first, and then click Next. Don’t worry about description. I’m going to go and click on Create access key.

Now, the reason why we’re creating this user is because we’re going to be using it to go and deploy out EKS using the CLI tool, which is the reason why we went and created our access key and secret access key. So go and make sure that you go and copy this and set it aside because we’ll be using it in a future lesson. That’s all I have. I am Travis Thomsen, and I’ll see you in the next one!.

Demo: Creating the Management Instance

Hello again! I’m Travis Thomsen. In this demo, we’re going to be going and creating a management instance to go and stand up our EKS cluster. Now, there is a wide variety of things we’re going to be using this instance for. We’re going to be using it to go and build our Docker images, along with going and deploying out our EKS cluster and also managing it. So the first thing we need to do is go and deploy out an EC2 instance running Amazon Linux.

We’re then going to go and install Docker on it. This way we can go and build out our Docker images. And after that, we’re going to go and update the AWS client to the latest version. So let’s go ahead and get started. I’m already logged into my AWS console, and I’m going to come up here to search, and I’m going to type in ec2.

Go and select EC2, and scroll down and look for Launch instance. Go and click on the button. I’m going to go and name my instance. I’m just going to go and call it Docker. Now scroll down.

We have Amazon Linux already selected. I’m fine with using a t2.micro. I don’t see the need to use anything bigger than that. The next thing we need to do is go and select a key pair, even though I will not be using one. Now, I created one previously, so I’m come over here and select eks.

I’m going to scroll down. Everything is good. I’m going to come over here to Launch instance, and I’m going to go and click on the button. Now it will take a few to go and launch this instance, and once it’s ready, I’ll come back. Now while I’m waiting for my instance to go and complete, I want to make sure you have access to all the commands I’ll be using for this lesson.

So, again, come over to GitHub and then riverhead42/node.js‑microservices‑deploying‑scaling. Come over here to Section05, go and click on it, and then over to lesson 2. And again, all the commands I’ll be running for this lesson can be found here. Now my EC2 instance is now online. I’m going to come over here and go and click on it, and we want to go and click Connect, and scroll down, and click Connect again.

This is going to go and open up this Terminal Window. I am going to go and make it a little bit bigger. And I’m going to go and then close this little box out here. Now, the first thing we need to do after going and deploying out any instance, we want to make sure that all the packages are up‑to‑date. So type sudo yum update and ‑y.

Looks like everything is up‑to‑date. I’ll go and clear my screen. And now we’re going to go and install Docker. So type sudo yum install docker, and then ‑y. Now, this will take a moment, so I want to go ahead and pause and let it go and finish installing.

Okay, my Docker packages are done installing. I’m going to go and clear my screen, and the next thing we need to do is make sure that we go and start the service. So type sudo service docker and start. Now that our Docker service is started, I can go and clear my screen. And we want to go and add our EC2 user to the Docker group.

So type sudo usermod ‑a, and then ‑G, and then the name of the group we’ll be adding our user to, which is going to be Docker, and then the name of the user, which is ec2‑user, and click Enter. Now for this to go and take an effect, we need to re‑log back into the user. So I’m just going to go and click Refresh. Go and close that out. And once everything is done connecting, I should be able to go and type docker ps, and we are connected to Docker.

Excellent. I’ll go and clear my screen again. I’m going to come back over here to my GitHub repo. I’m going to scroll down, and I want to go and grab this address right here. What we’re going to do is we’re going to go and install the latest version of the AWS CLI.

So I want to go and curl this URL and download it locally. I’m going to come back over to my instance, and I’m just going to go in, paste this in, and then hit Enter. Now that we have our file, we’re going to go and unzip it. So type unzip, and then the AWS .zip file. This will take some time to go and extract, so I’m going to go ahead and pause, and we’ll resume once it’s done.

Now everything is done extracting, I’m going to go and clear my screen yet again. And now we need to go and install the changes. So type sudo ./, and then aws/install ‑‑update, and this will go and update the CLI tool. And if we go and type aws and then ‑‑version, you’ll see that we now have a newer version, which is 2.15.6. And this completes the demo.

I am Travis Thomsen, and I’ll see you in the next one!.

Demo: Creating the EKS Cluster

Hello again! I’m Travis Thomsen. In this demo, we’re to go and deploy out our EKS cluster. That’s right, the wait is finally over! We have our prereqs in place, we have our management instance deployed out, and everything’s been installed. We’re now ready to go and get things set up for EKS. So, what do we need to do to pull out EKS? Well, first off, we need to go and install the command‑line tool, eksctl.

This is what we’re going to be using to go and communicate with aws and install EKS. Now, we could go and take care of this manually, but deploying EKS is actually rather complicated, and there is a lot of things that need to be done. So rather than going and using just the AWS CLI or installing it using the AWS console, we’re going to use eksctl because it’s going to make our lives so much easier. Now, we also need to go and install kubectl, and this is what we’re going to be using to go and interface with Kubernetes. And finally, we’ll be going and creating the cluster.

So let’s go and get started. You have access to all the commands by going and heading over to my GitHub repo for this course, which is nodejs‑microservices‑deploying‑scaling. Come over here to Section05, and then click on Lesson 03. And again, we have all the commands here that I’ll be using. Now, I’m already logged into my EC2 instance.

I’m going to go and clear my screen. And the first thing we’re going to be doing is setting the architecture of the file that we want to download, which is going to be amd64. Next, we need to go and set the platform where we’re setting that equal to $, and then in parentheses, (uname ‑s), and then underscore and the variable for the ARCH that we just set. Now we’re ready to go and download the file, which we’ll be using curl. And again, it’s going to be a lot easier if you just come over here to the GitHub repo and just go and grab that right there.

You see that we have downloaded the ekscatl, which is going to be Linux, and then amd64. Now let’s go and un‑tar this file. And to do that, we’ll be executing tag ‑xzf, and then the name of the file, and we want to make sure that we’re going to be putting this into tmp, and then we’re going to go and just remove the tar.gz file once we’re done. And now we want to go and copy the file over into /user/local/bin. That way we have access to it throughout the console, and we don’t have to worry about supplying the full path to the file.

To do that, we’ll be typing sudo mv, and then /tmp/eksctl, and then we’ll be placing it into /user/local/bin. Okay, now that etctl has been installed, we need to go and install kubectl. If you have not worked with Kubernetes before, kubectl is the command‑line interface tool we’ll be using to go and interface with our Kubernetes cluster. This is what we’ll be using to go and manage pods, services, as well as deployments. So one of the most important things we’re going to be doing is setting the version of EKS, and the version I’m going to be using is 1.28.0, and that minor version is very important.

We want to make sure that we always use .0. Now to find out what is both supported by AWS and eksctl, we have to go and check the documentation. Now, I do have a link over in the GitHub repository, and if you go and scroll down, just look for eks.io, and then getting started. I’m going to go and open this into a new tab. And we’re going to go and scroll down, and we’re going to be looking for EKS supported version.

So, 1.23 all the way to 1.28 is what is supported. Okay, now we’re going to go and curl that package. You just come back over to the GitHub repository, and you can get that curl command right here. I’m going to hit Enter and download kubectl. Now, before we use it, we want to make sure that it’s executable.

So type chmod +x and then kubectl. If I do an ls, you can see that we now have the ability to go and execute kubectl. And last, but not least, we want to make sure we have the ability to go and execute kubectl from anywhere. So we’re going to go and move kubectl over into /user/local/bin. I’m going to go and clear my screen.

Before we’re able to go and deploy our EKS cluster, we need to make sure that we have the proper credentials set. And to do that, so we need to type aws configure. Now because I am dealing with sensitive information, I’m going to go and blur out my access key, as well as the secret access key. So I went ahead and I pasted in my access key, and now I want to go and supply my secret access key. I want to go and set up a default region.

So I’m using us‑east‑1, and then the default output format I’m just going to leave as None. All right, we are now ready to go and deploy out EKS. Okay, we have a lot going on with this command. So we’ll be executing eksctl. We’re going to be creating a cluster, so we supply create, and then cluster, and then we need to go and name the cluster.

So do that, we’re going to be supplying a flag, which is ‑‑name, and I’m just going to call this pscluster. Now, the next two flags are going to deal with autoscaling, and this is something we’ll be talking about in the future. Just be aware that we want to have a minimum nodes of 3 and a max of 4. This information is going to be used to go and create our autoscaling group. So to start this off, we’re going to be using ‑‑nodes‑min, and we want the minimum value to be 3, and then ‑‑nodes‑max, and we want to have a maximum nodes of 4.

Now, we’re also going to be using the instant selector flags. Now because I am using my personal account, I want to make sure that I keep these instances as small as possible. And to do this, we’re going to be using ‑‑instance‑selector‑vcpus, and I’m going to be setting this to 2, and then ‑‑instance‑selector‑memory, and we’re going to be sending that to 4. Now, if you’re following along with your personal account, you will probably want to do the same as well, and just be aware that you will be charged when you go and create these instances, so I would not leave them lingering, and I’ll show you how to go and delete them at the end of the lesson. And last, but not least is the version of EKS we’re to go and deploy out, and this needs to match the version of the kubectl tool that we went and downloaded because if it doesn’t, it’s not going to work.

So, use the flag ‑‑version and set it equal to 1.28. So I’m going to go and pause right here, and we’ll resume once everything is done. Okay, so my deploy did complete. I do want to point out that initially it did fail, not because anything was done wrong, but for whatever reason, CloudFormations was unable to go and create the round tables, sometimes entropy does happen, and all I had to do was go and delete the stack and rerun the command and everything worked fine. So if you run into issues yourself and it is not related to anything that was done wrong with the way we configured things, just go delete the stack and try again.

Now to make sure that everything did install properly, we want to make sure that we have, we see this right here, and the fact that we do have the ability to go and execute kubectl, because if you get a failure here and you are seeing red, this means that kubectl cannot communicate with the EKS cluster. The most likely reason that this is happening, it means that you got the version wrong. Let’s go and test things out. You can type in kubectl and then get all. So when we go and execute kubectl get all, we’re getting everything back from Kubernetes.

This includes pods, services, ReplicaSets, and deployments. And what you’re seeing here is the service for the public‑facing API that kubectl uses to go and communicate with Kubernetes with. So now let’s go back over to the AWS console. And if we go to Instances, you can see that we do have the nodes for the EKS cluster. I’m just going to go and adjust my screen size so you can see more of what’s going on here.

But we do have c5.larges for our instances, and there are 3 of them, and this is what we specified when we went and deployed out the EKS cluster. Now, I do want to point out that if you really wanted to, you could go and spin up a bunch of EC2 instances yourself and install Kubernetes and get all the networking going, but quite frankly using eksctl is so much easier. It’s going to save you so much time. Now, before we go and call things done, let’s head back over to our Terminal Window. Let me go and make it bigger again.

And let’s talk about deleting the cluster. Now, I’m not going to go and delete my cluster just yet, but I want to show you the commands. That way you have the ability to go and delete it, just in case. Like I said, these are costly resources, and we want to keep this expense to a minimum. So if you want to go and delete your cluster, you’re going to be using eksctl delete cluster, and then we just supply the name of the cluster, just like when we went and created it.

So if I was to go and run this command right now, it would go and tear everything down. I don’t have to worry about going over to CloudFormations and deleting the stack. This handles everything for me. Okay, that’s it. We’ve successfully gone and deployed out the EKS cluster.

I’m Travis Thomsen, and I will see you in the next one!.

Code Examples

# Installation de eksctl
ARCH=amd64
PLATFORM=$(uname -s)_$ARCH
curl -sLO "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz"
tar -xzf eksctl_$PLATFORM.tar.gz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin

# Installation de kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

# Création du cluster EKS
eksctl create cluster \
  --name bevco-cluster \
  --region us-east-1 \
  --nodegroup-name standard-workers \
  --node-type t3.medium \
  --nodes 3

Demo: Create an ECR Repository

Hello again! I’m Travis Thomsen. And now that we’ve gone and deployed out our EKS cluster, we need to go and set up some repositories for our code. So what we’re going to be doing is we’re going to be creating four image repositories for our application. This means we’ll be creating some ECR repositories along with going and making sure that our EKS cluster has access to those repositories. So we need to go and set up a new IAM policy, and then we’re going to go and attach it to one of the EKS nodes, which ultimately will be for all of them.

Once we’re done, we want to go and test out our configuration by going and creating a Docker image, pushing it to a repository, and then going and deploying out a pod to our Kubernetes cluster. So let’s go and get started. Now, if you want to have access to all the commands I’ll be running throughout this lesson, just go over to my GitHub repository, go to Section05, and then on Lesson 04. Because of the way the microservice is set up, we need to go and create 4 repositories. But for right now, I’m just going to create one just as a test to demonstrate what you need to do to get everything set up, and then at the end, I’m going to go and create all 4 of them.

So the command we’re going to be executing is going to be aws ecr create‑repository. And then we need to go and supply a name, which is going to be ‑‑repository name. Now, I just have a placeholder here. I’m going to go and remove it. And I’m just going to call this one tthomsen‑test‑image.

And next we need to go and supply the region of where we want this to go, which is going to be us‑east‑1. And the flag for that is going to be ‑‑region. And we get this JSON back, meaning that everything was created successfully. And if I come back over to the console and I type in ecr, and I can go and click on Elastic Container Registry, we should be able to go and see the repository that was created. So here we go.

We have tthomsen‑test‑image. If I go and click on that, let me go ahead and make this a bit smaller so you can see it better, you can see that nothing has been pushed to it just yet. Now, in order for our Kubernetes nodes to be able to go and access the registry, we have to go and create an IAM policy. So let’s do that right now. I’m going to come over to search and type ec2 because we want to do this from the EC2 instance.

Come over to Instances. We want to make sure that we grab one that’s a part of the Eks cluster. So I’m going to go and select this one right here, and I’m going to be looking for IAM. Here we go. I’m going to go and click on IAM.

And when I go and I add this policy, it’s going to affect all the nodes that are in the cluster. So I’m going to come over to Permissions, and click Add permissions, and then create inline policy. And this is very similar to what we did at the very beginning of this section. So I’m going to come over here and click on JSON. I’m going to go and just delete everything here and paste in my policy.

So this is going to allow EKS to be able to go and talk to ECR. So I’m going to go and scroll down and just click Next. And I’m going to go and name this policy ecr‑policy. And then scroll down, and then click on Create policy. Okay, so we should be good to go.

Let’s go and test things out. So I’m going to come back over to the console here. I’m going to go ahead and make this a little bit bigger. Okay, so what we’re going to be doing here is we’re going to be using aws ecr get‑login‑password, and we need to go and supply the region, which is going to be us‑east‑1, and then we’re going to go and pipe it to Docker. So we’re piping into Docker login, and we’re using username AWS, and then password‑stdin.

And we need to go and supply the registry. So do that, I’m going to come back over to the AWS console and look for ECR, and I’m going to go and grab the registry that we went and created. So I want to go and click here to go and copy the URI. Come back over to the console here and just go and paste that in. And this is what we’re going to be using to go and log in.

Okay, it says WARNING! Your password will be stored unencrypted. How it easily is done with Docker, and it’s going to be stored in /home/ec2‑user/.docker/config.json. So yes, this is a bit of an issue that we are storing the password locally, but again, it’s not on screen. If somebody really wants to find it, they can. And all you have to do is just go and delete the file.

Okay, so as you can see, we have successfully logged in. Now we’re ready to go and create our Docker image. So let me go and clear my screen. And in here, I’m just going to create a directory called docker‑test, and we’ll go and navigate to that directory. Create a new Dockerfile.

And this is going to be really easy. So all we’re going to do is we’re going to use one instruction, and that’s going to be FROM, and then nginx. I want to make sure that this is not capitalized. Okay, that’s all we’re doing. So this is our very simple Dockerfile that we’re creating, and we’re going to be pushing it over to the registry.

Type docker image build. We need to go and tag our image, so use ‑t, and then supply the name of the tag. So when I come back over to the console, I go and grab that, and then paste it in. And when we do this, we’re going to do colon and then latest, so this is going to be the name of the image. So we’re going to be supplying the URI for the repository and then :latest, so the latest is going to be the tag.

You know what, I forgot to do dot. Dot lets Docker know that you’re going to be using the Dockerfile in the current directory. Now to make sure that things built correctly, I’m just going to do a Docker image and then ls, which is going to go and list all of our images. And as you can see, there is the image we just created. So now we’re ready to go and push our image to the container registry.

To do that, type docker image push, and then again the name of the repository. So I’m going to go and grab the URI once again. I’m going to go and paste it in. And then we tagged it as latest, and as you can see, our image is pushed to the registry. All right, everything is done.

And if I come back over to the AWS console and I click Refresh, I go and click on that, and again, let me make this a little bit smaller so I can see it properly. Oh, that’s big. There we go. You can see that we have the latest image. Excellent! Now we’re ready to go and deploy out a test pod to our Kubernetes cluster.

So, again, I’m going to make this a little bit bigger here. Come back over to the console and then clear my screen and type vi pod.yml. Now I already have this predefined pod set up, we’re ready to go. The only thing that we need to go do is change the repository that we’re going to be using. So let’s go ahead and do that now.

So I’m going to go and remove this. Come back over to the console. I’m going to come back here. And then, actually, I want to go to repositories, and then copy the URI, and then paste it in. When we go and build out our YAML files, I’ll be covering this in more detail then.

But for right now, we just want to make sure that everything works right. So let’s go and save and quit. Now, all we need to do is go and deploy the pod out, and to do that, we’re going to do a kubectl apply because we’re going to be applying this file, ‑f, and then the name of the file, which is pod.yml. Okay, it says it’s been created. And I can do a kubectl get all.

And as you can see, we have our pod running. So let’s go and finish things off by going and creating the four repositories that we need to go and deploy out our microservices. So I’m going to go and clear my screen. Before I go and create these other registries, I just want to go make sure I clean things up by going and deleting the pod. So, execute kubectl, delete, again, ‑f, and then the name of the file, which is pod.yml.

Oh, and I misspelled it. Go figure. If I do another kubectl get all, you can see that the pod is now gone. The repository I’m going to create first is going to be for the API gateway. Much like before aws ecr create‑repository, we supply the name of the repository.

I’m just going to call it tthomsen‑bevco‑api‑gateway. And again, we’ll be supplying the region, which is going to be us‑east‑1. Okay, everything looks good. And go clear my screen, and go and create the next registry, and this one is going to be for the inventory microservice. So this one’s going to be called tthomsen‑bevco‑inventory.

Make sure when you go and create your registries, you make it specific to you. Obviously, don’t use my name, use yours. That’ll make things a lot easier. That one is created. Now I’ll be creating the registry for the inventory messaging.

The only thing we’re doing different here is we’re supplying a different name, which is going to be tthomsen‑bevco‑inventory‑messaging. Everything is created. And now we have our final registry we’re creating, which is going to be tthomsen‑bevco‑restock, and this is going to be for the restock microservice. All right, we’re good. And if I come back over to the container registry, scroll up and just refresh here, you can see that we have all of them here.

Now, one last thing I’m going to do is I want to go and delete this test right here. So to do that, I’m just going to go and select that. Come up here and just click Delete. I need to go and confirm, so I’m going to type delete, and then click the Delete button. And we’re good.

All right, this completes everything that we wanted to accomplish in this demo. Now we’re ready to go and start containerizing our microservices. I’m Travis Thomsen, and I’ll see you in the next one!.

Code Examples

# Créer un repository ECR
aws ecr create-repository \
  --repository-name bevco-api-gateway \
  --region us-east-1

# Se connecter à ECR
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS \
  --password-stdin <account-id>.dkr.ecr.us-east-1.amazonaws.com

# Builder et pousser l'image
docker image build -t <account-id>.dkr.ecr.us-east-1.amazonaws.com/bevco-api-gateway:latest .
docker image push <account-id>.dkr.ecr.us-east-1.amazonaws.com/bevco-api-gateway:latest

6. Containerizing Your Node.JS Microservice

Demo: Containerizing Microservices

Hello again. I’m Travis Thomsen. In this demo, we’ll start containerizing our very first microservice. Now the first thing we need to do is go and inspect our code. Specifically, we need to look at the package.json file just to see how our app is going to be executed in production.

Then we’re going to go and create a Dockerfile. This is going to contain everything we need to go and build an image using our code. And then finally, we’re going to test everything out by going and building that image locally. And then once we’re done, I’m going to challenge you to go and pick another one of the microservices and see if you can containerize it yourself. If you can’t, no big deal.

We’ll have another video to go and show you how to go and containerize the rest of the microservices. Okay, let’s get started. To find the code that we’re going to be working with, just navigate over to github.com/rivethead42. And then come over here and click on Repositories, and we’re going to go and search for it, which is going to be bevco and then inventory. And it should be the very first one here, bevco‑inventory.

Come over here and click on Code. We want to make sure that when we go and clone it, we’re using HTTPS. And then come over here and click Copy to clipboard. Now, I’m already logged into my EC2 instance. And the first thing I want to do is I’m going to go and make a new directory.

So type mkdir and then code and then go and navigate to the code directory. Now we’re going to go and clone our repository, so type git clone and then paste in the repository URL. And if I do an ls, you can see that we have the bevco‑inventory microservice. So I want to go and navigate to that directory, clear my screen, and do an ls. Now the first thing we want to do is go and take a look at our package.json file.

Oops, didn’t mean to do that. Okay. What we need to do is we take a look at our scripts here, and this is going to give us some information about how we go and work with our application. Because we’re using TypeScript, we need to go and compile that, and we’re going to be using npm run and then tsc. This will go and compile our code down into JavaScript.

Now, we have a couple of start commands. Obviously, the one that says start and then ts‑node‑dev is going to be for when we go and work with our code locally. The one that we want to use is start:prod. And if we take a look here, it’s going to be executing node build/index.js. Now, the other file we need to take a look at is going to be tsconfig.

So we need to find out where our code is being compiled to. And what I’m looking for right here is the outDir. So it’s being built into build. Okay, so we have our start command and then we have where our code is being compiled to. And this is going to be a very important when we go and build out our Dockerfile.

So I’m going to go and just go ahead and quit. I’ll clear my screen, and we’ll start working on our Dockerfile. And the way we name the Dockerfile is it’s going to be Docker with a capital D and then file. I’ll go and put myself in insert mode. And the first thing we need to do is we need to go and pull a base image.

Anytime that we’re working with Docker, there are prebuilt images out there we can go and build on top of. And the one that we’re going to be working with is going to be from Node.js. So I’m going to open up a new tab, and I’m going to go and navigate over to hub.docker.com. And this is where you can go and find official images. So if I come over here and just type node, you see that we have node right here and that this is an official Docker image.

This will provide you with all the information you need to go and work with this base image. And this base image is going to come with Node.js already preinstalled. I’ll come back over here. Whenever we’re working with Docker instructions, they all need to be capitalized. So the first instruction we’re going to be using is from, and from is going to be the base image that we’re going to be working with.

In this instance, we’re going to be working with node and then :alpine. What we’re going to be doing is creating a multistage build. What this allows us to do is set up multiple images. The first one is going to be our build image, and we’re going to use this image to go and install our dependencies and compile our code. The second one is going to be our final product.

So we’re going to go and copy all of our necessary files over to that image. And then, that will be the one that will be created, and we’ll be pushing that one to the registry. Now the reason why we’re using a multistage build is that we want to keep our final product as small as possible. And we don’t need to include any of the junk that we’re using to go and compile our code. So we don’t need any of our dev dependencies, just what we need for production.

What we’re going to do is use the as instruction to go and name the stage. And we’re going to call this BUILD_IMAGE. And then after that, we want to go and set our working directory. So I’m supplying the instruction of WORKDIR, so this will be our working directory. Anytime we execute a command like copy or run, it’s going to be executed from this directory.

And the directory is going to be app, and I want this to be lowercase, Our next command is going to be copy, and we’re going to go and copy everything over into /app. And the way we do that is by supplying the instruction of copy and then period with another space and period. So we’re copying everything from our local directory of where the Dockerfile is, and it’s being copied into /app. Now we have some commands that we want to run. So we’re going to be executing the run instruction.

This allows us to go and execute something from the command line. In this instance, it’s going to be npm install. So right now we have everything copied over. This includes our package.json on file. So this allows us to go and install all of our dependencies.

This will also include any dev dependencies as well because we’re going to go and build out our application. And now we’re going to go and compile our code. So type run and then npm run tsc. So this is going to go and compile our TypeScript code down to JavaScript. Okay, so that’s all we need to do for our build image.

We’re going to be doing another from. So we’re going to be telling it that we’re going to be building out another image, and we’re going to be using node. This will be 21‑alpine. So this is the version of Node.js we’re using. We’re going to be using version 21.

And now we have some environment variables we need to set up. Because we’re running production, we want to specify that NODE_ENV is going to be production. So we’re supplying the arg, which stands for argument. And this will allow us to go and pass in the environment that we want to go and use. But we’re going to setting it to a default of production, so we don’t need to worry about going and passing a flag to make sure that NODE_ENV is set to production.

So node_env is going to be equal to‑‑‑ It’s going to be equal to production. All right, now we’re going to set the env instruction, and we’re going to be setting NODE_ENV. And I just realized that this is wrong here. And then, we’re going to supply the variable, which is going to be NODE_ENV. Okay, So that should make sure that we are running our environment as production.

Now we want to make sure that our container is not running as root. We’ll be creating a user that our code will be executed as. So let’s go and take care of that. We’ll be using the run instruction. And we’re going to first go and add a group.

So add group ‑g, and we’re going to supply the ID for the group, which is going to be 1001 and then ‑S. And the name of the group is going to be nodejs. Now we’re going to be doing the exact same thing here. But this time, we’re going to go in adduser ‑S and then nodejs. We’ll be supplying an ID, which is going to be 1001.

And just like before, we need to go and set our working directory, so WORKDIR, and then it’s going to be /app again. Okay, now that we’ve established our working directory, we need to go and start copying our files over from our build image. So we’re using the copy instruction, and we’ll be supplying ‑‑from. We’ll be setting that to BUILD_IMAGE. We’re naming the image that we created in the first stage.

We’re just making sure that we’re going to be copying from that image. We also want to go and chown our files. We want to make sure that they’re under the ownership of user in group nodejs. So this will be like executing a chown from the command line. And what we’re copying over is going to be /app and then package.json.

And we also want to get the package‑lock file as well, so app/package and then ‑lock.json. And we’re going to be copying it into ./. So this is going to copy these two files into /app. Now we need to go and copy one more directory over, so we’ll be using the copy instruction. And like before, we’ll be using from, but let me make sure it’s all lowercase, and then BUILD_IMAGE.

And then, we’re going to be chowning our file again. We’ll be sending that to nodejs:nodejs. And what we’re going to be copying is app/build. So remember how we went and inspected the files to make sure that we know where our code is being sent to. It’s being built and /app/build, and we want to copy that over to ./build.

All right, we are almost done. Next up, we need to go and execute a run command. And what we’re doing is we’re going to do an npm install, but we want to make sure that we provide the environment. So we’ll be supplying NODE_ENV, and we’re going to be setting that equal to $NODE_ENV. And then we just do an npm install.

So we want to make sure that we’re only installing production packages and not the dev ones because we don’t need anything going and cluttering up our image and making it larger. We want these images to be as small as possible. Now we’re ready to go and define our user, so we’ll be using the user instruction and then supplying nodejs. And finally, we’re going to go and execute our code. So this is going to be the entry point into our container using the cmd command.

This is going to be an array. Essentially what we’re doing here is that we’re breaking up the command that we’re going to be executing by spaces. So, the first one is going to be npm. And then after that, the next one is going to be run. And then my last command is going to be start and then :prod.

And remember, the start command is what we’re getting from our package.json file. So if you have any questions, I would refer you back to the package.json file to see how you go and start up your application. Now we can go and save and quit. Before we go and push our code to the remote repository, we want to make sure that our code works locally first. In order to do that, we want to go and build our image locally.

So to do that, type docker image and then build. Now the next thing we want to supply is a tag because if we don’t tag it, it’s just going to be unnamed, so use it. And then we’re going to be calling this inventory‑test. It’s always a good habit to go and tag it with something like latest or an ID. We’re going to tag this as latest.

If we don’t, it will tag it the latest by default. And then we want to supply a period to go and make sure that we’re using the current directory. Now this is going to take some time to go and build out. So I’m going to go and pause and we’ll resume once it’s done. All right, the image is done being built.

Let me go and clear my screen and do a docker image ls. Now as you can see here, we only have one image, and that’s because the image that was used during the build stage gets discarded once everything is done. All right, now that we’re done building our image, we can go and test it out by going and deploying out a container. So type docker container and then run. We want to use the ‑d flag which is going to detach us.

This means that we’re not going to be attached to our container, and this will go and run the container in the background. Now we supply the name of the image we want to use, which is going to be inventory‑test and then hit Enter. You can see that we get an ID back. If I clear my screen and do a docker ps, you can see that our container is actually running. Now what I could do is I can go and view the logs on it.

So docker container and then logs, and we supply either the name of the container or the container ID. And you can see that we’re getting a Mongoose error, and this is fine. And the reason why we’re getting an error is that we don’t have a MongoDB that we’re connecting to. So this means that our image is now working. Now like I said at the very beginning of this video, I want you to go and challenge yourself.

Go and pick another one of the microservices and go and try and containerize it. I’m going to give you a hint. The Dockerfile that we just created will work for all of our microservices. So go, see if you can go and build out an image and get it working yourself, and then I’ll follow up with you in the next video, which is where we go and containerize the rest of our microservices. And if you need a cheat sheet, you can head over to the GitHub repository for this course and reference the README file for this demo.

It contains all the commands that I used along with the instructions for the Dockerfile. I’m Travis Thomsen, and I will see you in the next one..

Code Examples

# Dockerfile pour un microservice Node.js TypeScript
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run tsc

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=build /app/build ./build
CMD ["npm", "run", "start:prod"]

Demo: Containerizing the Remaining Microservices

Hello again. I’m Travis Thomsen. In this demo, we’re going to go and complete what we started in the previous one, which is containerizing the rest of our microservices. Much like with the previous microservice, we’re start by going and inspecting the code for each one of the microservices. And this will go and tell us how we can go and containerize our application.

We’ll also be creating a Dockerfile for each of our microservices. And then much like before, we’re going to go and build them out just to make sure that things work locally. Okay, let’s go and get started. Go and navigate over to my account over at GitHub, which is github.com/rivet head42. And again, come over to Repositories, and we’re going to go and pick a random one.

I’m going to start off with bevco‑restock. We want to go and clone our code, so come over here to Code. Click on that. And we want to make sure that we have HTTPS selected right here and then copy the clipboard. Back over at my instance, if I do an ls, you can see that we have the code directory.

Let’s go and navigate to that and then git clone. I’m going to paste in the repository link. And when I do an ls, you can see that we have the restock microservice. I’m going to go and navigate into that directory. And much like before, if I go and I take a look at the package.json file, oops.

Now under scripts, you can see that our package.json file is exactly like the previous one. As you can see, we have tsc, which is going to go and compile our TypeScript code down into JavaScript. And then we also have start prod. Likewise, we have a tsconfig file. Let go and take a look at that.

Okay, so we’re looking for the outDir. It’s right here. And just like the other microservice, we’re going and compiling our code into the build directory. So now we’re going to go and create our Dockerfile. And again, the name of the file has to start with the capital.

Now I already went and typed this out before, and I’m sure you don’t want me to go and repeat this. So I’m just going to go and paste it in. I’m going to go back up to the top. Much like before, we’re starting off by going and supplying the default image we’re going to be working with. So we have our from instruction, and the name of the image that we’re going to be supplying here is node:alpine.

Now I want to go and specify this as our build image, so we have as and then BUILD_IMAGE. Next, we’re going to go and set up our working directory. We’ll go and copy all of our files over into /app. Then after that, we run an npm install. This is going to go install all of our dependencies, including the dev ones.

And then finally after that, we’re going to go and compile the code by going and executing npm run tsc. Okay, so now we’re getting over to the real image that is going to be built. We’re supplying our default image. This time we’re using node, and then it’s going to be 21‑alpine. We are specifically tying it to a version of Node.js, which is version 21.

After that, we’re going to go and supply an argument, and the argument is going to be node environment, and we’re going to go and set it equal to production. Now when we go and build our image, we do have the ability to go and override this argument, but we’re not going to. And then, we’re setting up an environment variable, which is going to be node environment, and we’re setting it to the argument we just created. Now whenever we run a container, we want to make sure that we don’t run it as root. So I want to go and set up a new group here, and that group is going to be nodejs followed by the nodejs user.

We’re also going to be telling it that we want to use /app as our working directory, and then we want to go and start copying files from our build image over to the image that is going to be our finished product. So we have another instruction here, which is going to be copied. And we’re going to be using the ‑‑from flag to tell it that we’re going to be copying from the build image. And when we do that, we want to make sure that we chown our files. We want to make sure that the user group is going to be nodejs.

So we have ‑‑chown, and we’re setting that equal to nodejs:nodejs. And we’re copying over two files, which is package.json and package‑lock.json. And again, it’s being copied into ./, which is going to be the working directory, which is /app. This time we’re doing the exact same thing here, but for the build directory. So we’re doing the exact same thing.

We’re copying over from the build image. We’re going to go and chown our files. And then we’re copying from /app build, and it’s going to be copied into ./build, which is going to translate to /app/build. Finally, we’re going to go and set our user, and we’re telling Docker that we want to use the Node.js user. That way when we go and execute our command, it’s going to be running as the Node.js user and not root.

And finally, we go and supply the command that is going to be executed when the container goes and starts up. And the way we do this, it’s going to be a comma‑delimited list, which is going to be npm run and then start:prod. All right, let’s go and save and quit. Now I’m going to go and test out our image by going and building it. So we’re going to go and run docker image build.

We’ll be passing the t flag because we’re going to go and tag our image. And since we were working with restock, we’re going to call it restock and ‑test. And then we end things with a period. Okay, I’m going to go and let this run, and we’ll resume once it’s completed. Okay, our image has completed building.

If I do a docker image ls, you can see that we have two images now. To make sure that everything is working right, let’s go and deploy a container. Execute docker container run and then use ‑d to go and detach and then the name of the image which is restock‑test. Okay, we have an image that started, so docker ps. You can see that we have two containers running right now.

Once we get done, we’ll go and clear everything out. I’m going to head back over to my GitHub repository. I’m going to click the back button here. I want to go and check out another one. This time, we’ll just go‑‑‑ We’ll go with the api‑gateway.

Again, come over here to Code. I want to make sure that we’re using HTTPS and then copy the link to clipboard. Let me go and back out of the restock microservice directory. And I’m going to go and clone this repository here. I’ll go and cd into bevco‑api‑gateway.

Much like before, we have our package.json file and our tsconfig.json file. So let’s go and look at package.json first. Okay, everything is exactly the same here. If I go and open up tsconfig.json and look for outDir, you see that our outDir is also built. Okay, so let’s go and start working on our Dockerfile.

I can go paste the contents of my Dockerfile in. We’ve already gone through it again. I’m just going to save and quit at this point. And now we can go and build the image, so Docker image build. Let me go and tag it, and this is going to be the API gateway so we’ll call it api‑gateway and then ‑test.

Okay, we’ll go and resume once this is done. Okay, the build is successful. Go clear my screen. Let’s go and test out our image. Now if I do a docker image ls, you can see that we now have three images.

We have our api‑gateway. All right, let’s go and deploy our container. It’s docker container run. We’re going to be using ‑d. Again, we want to detach.

We supply the name of the image, which is going to be api‑gateway and then ‑test. I’ll do a docker ps. You can see that we now have three containers running. All right, let me come back over to the GitHub repository. I’m just going to click that back button.

We’ve done restock. We’ve done api‑gateway. We’ve done inventory. What we need to do is make sure that we get the inventory messaging system next. Come over here to Code.

Make sure that HTTPS is selected. Come over here and click Copy to clipboard. Back over to my console and go and back out of this directory. Do a git clone, and then I’m going to paste in the URL. All right, and now we have our messaging code.

Okay, if I do an ls, again, I can tell you much like before if I go over here to package.json, we have the exact same setup under scripts, which is tsc and then start prod. Same thing for our file here. I go and search for outDir. We can see it’s set to build. Now let’s go and create a Dockerfile.

And I’ll paste my code in. All right, everything looks good. Let me go save and quit. Now let’s go and build the image, so docker image build. And again, we’re going to be tagging it.

Since this one is inventory messaging, I’m going to call it inventory‑messaging and then ‑test. Oh, I forgot my period. Okay, build has completed successfully. I’m going to go clear my screen. Okay, so let’s go and deploy out a container.

So docker container run, and we named this inventory‑messaging‑test. And I want to make sure that I do run this as detached. So I’m going to be using the ‑d flag. And if I do a docker ps, you’ll see that we do not have our container running. And there is actually a very good reason why it’s not.

So if I do a docker ps-a, we get a list of all of our containers. You can see that we have our messaging container right here. I’m going to go and copy that and do a docker logs and then paste that in. You can see that we have a long list of errors. Now everything actually is working as intended.

You can see that we tried to go and connect to MongoDB, but there is no MongoDB. And we’re also going to go and try and connect to a non‑existent RabbitMQ server, which is the reason why we’re getting this error here. So everything is done. Okay, that’s all I have for this demo. I’m Travis Thomsen, and I will see you in the next one..

Demo: Pushing the Images to the Container Registry

Hello again. I’m Travis Thomsen. And in this lesson, we’re going to go and push our images to the container registry. So the first thing we need to go do is rebuild our images. And the reason why we need to do this is that the name of the image needs to match up with the name of the registry where we’re going to go and push the image to.

And after we go and rebuild it, we can go and push the image to the AWS container registry that we have gone and set up for each of the microservices. So let’s go ahead and jump into it. We’re going to start things off by going and navigating into our code directory, so cd and code. In here, we have all the code where we went and created the images for our microservices. So I’m going to start things off by going and navigating into the bevco‑api‑gateway.

Okay, so we’re going to go and start off with this microservice. I need to head over to AWS, and I need to go find the elastic container registry, so ECR. I’m going to scroll down, and I’m going to go and find the bevco‑api‑gateway, which is right here. So I’m going to go and copy this. I go to my console, and I’m going to do a docker image build -t.

Now I need to go and supply that name. As you can see, this is the full URI to the registry. The last thing I need to do is:latest. Oh, and I forgot to add in the period. Okay, so now that we’ve gone in, rebuilt the image, I do a docker image ls.

Let me go and fix that typo. You can see right here we have the image that we just created. Now we need to go and push it to the remote repository. To do that, we do a docker image push. But you know before that, I think we need to make sure that we have logged in.

So I have my login command here. We have aws ecr get‑login‑password. We’re going to go supply the region, which is us‑east‑1. And then we’re going to go and pipe it to docker login. We have a flag, which is username, supplying aws and then password‑stdin.

Now I need to go and grab that registry yet again. Okay, we have successfully logged in, and now we can go and push the image. Execute a docker image push, and we supply the name of the image, which is the URI, and then latest. If I come back over to the container registry and I go and I click on it, you can see that we have the latest image. Okay, so now let’s go and do another one.

Back out of that directory, do an ls, and let’s do bevco‑inventory. So I want to execute a docker image build ‑t. You come back over here and get the name of that repository. Here we go, right here. Paste that in and then: latest and then period.

Okay, everything is good there. Now one of the things that you may have noticed is that these images are building very quickly. And the reason why is because they’re using cached layers. So if there’s no changes, it’s going to go and use those cached layers. So if we ever want to go and rebuild it and not use cached, you can use ‑‑no ‑cache, and that will completely rebuild the image from scratch, ignoring anything that has been previously cached.

Let’s go and push the image to the repository, so docker image push. Let me actually go and correct that. And then the name of the image and :latest. Okay, image has been pushed. Go and drop‑down directory, and we’ll do bevco‑inventory‑messaging next, docker image build, again ‑t.

Come back over here. We’ll go and grab this repository right here. Go and paste that in and then tag it as latest and then end it with a period. All right, everything’s good, docker image push. Supply the URI and then latest.

And this will push it to the remote. All right, we have one left, and that’s the restock microservice. We’ll do docker image build, again supply the ‑t flag because we’re tagging it, and grab this one right here. We go and paste that in and then latest and period. Okay, I want to go and push it, so docker image push, paste in the URI, and then latest.

Okay, now that we have all of our images pushed to our container registry, this means we can move on to the next step, which is going and deploying our application. I am Travis Thomsen, and I will see you in the next one..

7. Deploying Your Node.JS Microservice to EKS

Demo: Deploying MongoDB Backing Service

Hello again. I’m Travis Thomsen. In this module, we want to start deploying out our microservices. But before we can do that, we need to go and start deploying out a MongoDB backing service for our inventory system. Now normally, I would tell you to use something like RDS to go and deploy out your database and use that as your backing service.

But because MongoDB is not supported, we’re going to go and deploy that out ourselves. We’ll start things off by going and creating a deployment manifest for our MongoDB database. And then we want to go and create a service to make sure that our application has the ability to go and communicate with the database. So let’s go and get started. Now just as a reminder, in case you get stuck, everything I do in this demo can be found in my GitHub repository for this course.

So head over to my account, which is rivethead42, go into Repositories, and search for nodejs‑microservices‑deploying‑scaling. And then come over to section 7 and then lesson 1. Everything you need is going to be right here. Now because we’re going to be writing a lot of code in this module, I decided to go and use VS Code and ssh in to my instance. And that way, we have a lot more real estate to work with than just that small window we were working with previously.

So if I do an ls, you can see that I am indeed on the instance. And the first thing I’m going to do is I’m going to go and make a new directory, and I’m going to call it manifest. I’m going to go and cd into the manifest directory. The file I’ll be creating is going to be called inventory‑mongodb‑depl. And because this is a deployment manifest and it is going to be a YAML file, we end it in yml.

So just like before, any time we go and we start off a new manifest file, we want to make sure that we supply the API version, so apiversion and then colon and we need to supply apps/v1. Now the kind is going to be Deployment, and we need to make sure that we do capitalize Deployment. This is very important. And next, we need to supply our metadata, so metadata:. So we’re going to go and name our deployment, and it’s going to be inventory‑mongo and then ‑depl for deployment, and that’s it.

So now we’re going to go and create our spec for deployment. The first thing we’ll supply is replicas. And we want to make sure that we go and set the number of replicas to 1. Next we need to go and supply our selector. And we’re going to be supplying a match label, so matchLabels.

It does need to be plural. And then we supply our match label, which is going to be app: and then Inventory‑mongo. Now when are we doing the exact same thing within our template. Under metadata and labels, we’re going to be calling it inventory‑mongo as well. All right, so let’s go and build out that template, so template.

We need to go ahead and make sure we indent and we’ll be starting off with our metadata. And this is where we supply labels and then app inventory‑mongo. We want to make sure that both of these match up because if they don’t, things are not going to work right. All right, after metadata, we need to go and supply our spec for our deployment. So this is where we’re going to go and define containers.

Now containers is going to contain a list of containers. Of course, we’re going to be only using one. We supply the name of the container here. And this is going to be, again, I’m just going to call it inventory‑mongo. I just realized that I did misspell that right here.

And then after that, we supply the name of the image, which is going to be mongo. All right, coming back all the way over, and we’re going to use three dashes. This is how we go and delimit multiple YAML files. And we’re just going to go ahead and include the service in here as well. So apiVersion, that’s what we start things off with.

And this time it’s just v1 because we’re working with a service. And we go and supply our kind, which is going to be Service. And make sure to capitalize the S just like before. And now we’re going to go and include our metadata. So include the name and then inventory‑mongo‑srv for service.

Okay, now we need to go and set up our spec. First thing we’re going to go and define is our selector. This is going to tell the service which pods it’s going to be rounding traffic to. Because this is a key value pair, we start off with the app. And again, it needs to match what we went and defined under our match label.

So it’s going to be inventory‑mango. Now we need to go and define our ports, so ports. And ports is going to take a list of ports. I’m going to go and provide the name for our port, which is going to be db. We also want to make sure we specify the protocol, and the protocol is going to be tcp.

And below, I want to go and supply the port, and the port is going to be 27017. And because I want to be thorough, I want to go and supply our target port. It’s going to be the exact same port, which is 27017. Okay, so that’s going to go and complete the file. Okay, now that we’ve got and created our manifest file, let’s go and apply it.

So kubectl apply and then ‑f and then supply the name of the file. Okay, so far, so good. We have our pod being created along with our service, and we can do a kubectl get all to go and list all of our pods and our services. Okay, now that we have our Mongo DB backing service up and running, we still have a problem with it, and that problem is persistent storage. Because pods and containers are ephemeral, any data that is actually written to the container, if the container goes and gets restarted or is recreated, all that data is lost.

So we need to go and solve this problem by introducing storage, which will be coming up in the next demo. I’m Travis Thomsen, and I’ll see you in the next one..

Code Examples

# Exemple de Service Kubernetes
apiVersion: v1
kind: Service
metadata:
  name: web-server-svc
spec:
  selector:
    app: web-server
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP
# inventory-mongodb-depl.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inventory-mongodb-depl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: inventory-mongodb
  template:
    metadata:
      labels:
        app: inventory-mongodb
    spec:
      containers:
        - name: inventory-mongodb
          image: mongo:latest
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: mongo-storage
              mountPath: /data/db
      volumes:
        - name: mongo-storage
          persistentVolumeClaim:
            claimName: inventory-mongo-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: inventory-mongodb-svc
spec:
  selector:
    app: inventory-mongodb
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017

Demo: Using EBS Volumes for Persistent Storage

Hello again. I’m Travis Thomsen. In this demo, I want to continue working with our MongoDB backing service by going and adding some persistent storage to it. Now I’m going to be honest with you. Before storage classes, working with volumes was kind of a pain.

You had to go and manually and provision out the storage, go and create a persistent volume within Kubernetes and then a persistent volume claim. But along came storage classes, and things got a lot easier. So now, all we need to do is install a driver, go and create that storage class and then a persistent volume claim, and things will get provisioned out automatically for us. So how do we go about doing this? So the first thing we need to do is go and install the EBS CLI driver. This is what we’re going to be using to go interface with AWS to go and provision out EBS volumes.

And then we’re going to go and create our storage class manifest file. This is going to tell Kubernetes that anytime that we want to go and use EBS, it’s going to go and provision out storage for us. So after that, what we need to do is we need to create a persistent volume claim to lay claim to that storage. And then what we need to do is go and update our manifest file and tell Kubernetes that we need to go and lay claim to a volume. And then finally, we’re to go and update the deployment for MongoDB to tell it to go and use the EBS volume.

So, let’s go and get started. Okay, before we start jumping into working with storage classes, I wanted to pull up the documentation real quick just to talk a little bit more about storage classes. Specifically, there’s a few things we be working with, which is going to be the provisioner. We have some parameters that we need to go and supply information and then our reclaim policy. So the provisioner is going to be what we’re using to tell Kubernetes to go and provision out our volume, and that is also going to have a series of parameters that we need to go and supply.

The other thing that is very important is the reclaim policy. What we’re doing here is we’re telling Kubernetes when we go and delete our pod or our deployment, what are we going to do with that volume? We can tell it to go and leave it lying around, or we can go and delete it. The other thing we need to look at is just some of the various providers that we have when it comes to different types of storage that we’re able to go and work with. Now, AWS used to be on here for EBS volumes. Instead, you have to go and work with an external driver.

So if you’re working with another environment, you can see the various types of storage that is provided here and supported. If you’re working with Azure, everything is handled by default. Everything else, for the most part, you’re going to have to go and use an external provisioner. So working with an external provisioner is exactly what we need to do to get EBS volumes working. Now before we’re able to go and get our provisioner working, we have to tell our cluster that we want to go and associate an IAM IOCD provider, which will allow us to go and install everything properly.

So when I come over here and I’m going to paste this in, we’re going to be using our command line tool, eksctl, and we supply utils associate‑iam‑oidc‑provider, and we supply the name of our cluster. And then, we’re going to go and approve it. So now that we have enabled that we can go and create our IAM role. So what we’re going to be doing here is we’re using eksctl again. We’re going to go and create IAM service account.

We need to go and supply a name, which is called ebs‑csi‑controller‑sa. We need to go and supply a namespace, which is going to be kube‑system. This is where all of our system pods run. We also need to go and supply the name of the cluster, so cluster and then pscluster. You supply whatever you named your cluster.

And then we need to go and provide a role name. So the role name here is arbitrary. This is the one that is used an example, so I’m just going to use that as well. We then use role‑only, and then we also need to go and attach a policy ARN. So the ARN here that we’re going to be using is arn:aws:iam::aws:policy/service‑role.

And this is going to be AmazonEBSCSIDriverPolicy. So this is something that already exists within Amazon, and we also need to make sure that we supply approve. Now this is going to take a bit of time to go and provision out. So I’m going to go ahead and pause, and we’ll resume once it’s done. All right, everything has completed, and I need to come back over to the Amazon console.

So go and navigate to IAM. So I’m just going to type IAM up here and click on IAM. And we’re going to be coming over here to Roles. Now what we’re looking for is the role we just created, which is AmazonEKS_EBS_CSI_DriverRole. Go and click on that, and we need to go and grab this ARN right here.

Coming back over to the terminal window, the command we’ll be executing is going to be, again, eksctl. We’re going to create add‑on. We’re going to go and name the add‑on, which is going to be aws‑ebs‑csi‑driver. Going to be supplying the name of our cluster in my instance. It’s pcluster.

And then we need to supply the service account role ARN, and this is the ARN we just copied. And we’re going to follow things up with ‑‑force. Okay, our add‑on has been created. So with that out of the way, we can now work on creating our storage class. So I’m going to go and clear my screen.

If I do an ls, you can see we have our manifest directory here. I’m going to go and create that in there. So I’m going to type vi and then storageclass.yml. And as always, we need to go and start by providing our API version, so apiVersion and then colon. Now this time the API version is going to be different with the ones that we worked with previously.

The one we are resupplying is going to be storage and .k8s.io and then /v1. And our kind is going to be, you probably guessed this, StorageClass. And both the S and C do need to be capitalized. Okay, so now we need to go and supply our metadata and the name of our storage class. So when we go and reference the storage class, this is the name we’re going to be referencing, which is going to be ebs and ‑sc.

Next up, we need to go and supply our provisioner, and the name of our provisioner is going to be kubernetes.io/aws‑ebs. So when we go and provision out our storage, it’s going to go and reference this provider that we’re setting right here. Okay, so our next parameter we need to set is going to be our volume bind mode, so volumeBinding and then mode. And there’s several ways we can go and bind. The one we’re going to be using is going to be WaitForFirstConsumer.

What this is going to do is that things are going to be left unbound until we actually have a pod or, I should say really, a container going in using a volume. So when we go and pull up our persistent volume claims, it’s going to be shown as unbound until we go and update our MongoDB database. Okay, we have our parameters and we need to supply a type, which is going to be gp2. What we’re supplying here is going to be the type of EBS volume you want to use. If we do not supply a type, by default, it’s going to use gp2.

So if I come back over to the console window and I just come back over to AWS and I go to EC2 and click on Volumes and create a new volume, you can see the type of options that we have available to us. So under Volume type, you have gp3, gp2, io1, io2. Those are all options we can use for the type of storage. But like I said, since this is just a demo, we don’t need to have anything crazy, so we’re just going to go and stick with gp2. So I’m going to go and save and quit.

And at this point, we can go and apply our manifest, so kubectl apply ‑f and then storageclass. If all goes well, our storage class is created, and we can go and list our storage class by typing kubectl get and storageclass. As you can see, we have ebs‑sc created. You can see that a reclaim policy is deleted. This means that when we go and delete our persistent volume claim, it’s going to go and delete the EBS volume by default.

That way we have nothing sticking around. If this is a production environment, you might I want to change your reclaim policy to be something different. That way you’re able to go and reuse your storage and not lose any of your data. Now I want to go and modify our Mongo deployment, so vi and then inventory‑mongodepl.yml. And then come all the way back up to the top and I’m going to create my persistent volume claim before we get into the deployment.

So I’m going to go and create my three dashes right here. And as always, we want to go and start off with apiVersion. And because we’re working with a persistent volume claim, we’re just going to be using the apiVersion v1. And then we go and supply our kind. Okay, so the kind is going to be PersistentVolume and Claim.

Next, we go and supply our metadata, and we’re going to go and name our persistent volume claim. I’m going to call it inventory‑mongo‑ebs and then pvc for persistent volume claim. Next, we supply our spec. Now under spec, there’s several things that we need to go and supply. The first one is going to be the access mode.

What this means is that when we go and attach the storage, what is it going to do? Is it going to be read/write once, which means that it’s only going to be mounting to one container. Is it going to be mounted to multiple containers? And because of these access modes is why we want to use external storage and not something that is local because if we deploy a container out to one node and we want to scale it across multiple nodes, it’s going to be using the local storage of that node. So for example, we have three nodes. And let’s say that our MongoDB server is on node 1. If we were to use local storage, it’s going to be written to that node, and that’s not something we want to do.

We want to make sure that if we go and scale up our pod that it’s going to be using something that is not tied to the individual node itself, which is the reason why we’re using EBS volumes. So accessMode, accessModes, and we’re going to go and tell it that we want to go and read/write once. Typically this is what you’re going to be using. Now we need to go and supply the storage class name, and this is the storage class we just created, which is going to be ebs‑sc. And then we have our resources.

And then we need to go and create our requests and then storage. Now storage is how much we want to go and use. So what I’m going to do is I’m going to supply 5Gi, which means that we’re using 5 GB. Now this is going to be dependent on your needs. So if you obviously have a very large Mongo database that you’re working with, you want to make sure that you have plenty of storage for that database.

But again, since we’re just doing this as an example, 5 GB is fine. Okay, so now that we have our persistent volume claim created, we need to go and modify our deployment. So I’m going to come down here. I come to containers. We go and create a new line here.

And what I’m going to be supplying is a volumeMount. The M in Mount needs to be capitalized. Here I’m going to go and supply the name of the volume. So that is inventory‑mongo‑storage. Now, this name right here is going to be something we’re going to be creating under our spec, which is going to be our volumes that we’re going to be working with.

So this is not referencing the persistent volume claim, but the volumes that I’m going to reference within the spec. So after that, we need to go and supply our mount path. It’s going to be /data/db, and this is where MongoDB stores all its data. And this is the thing that we want to make sure is persistent. Okay, on a new line, I’m going to come back all the way and I want to make sure that this is going to line up with containers here, and we’re going to go and define our volumes.

Okay, we’re going to go and supply the name, and it’s going to be the name that we just supplied under volumeMount, which is going to be inventory‑mongo‑storage. And now we’re going to go and define our persistentVolumeClaim. And then we supply the claim name. And this is where we supply the name of the persistent volume claim we just created. So inventory‑mongo‑ebs and then pvc.

Okay, let’s go and save and quit. Now, all I need to do is just reapply my manifest. It’s going to go and update everything. So type kubectl apply ‑f and then the name of our manifest file, which is inventory‑mongodb‑depl.yml. All right, so it looks like I have an error, and I need to go and correct it.

Okay, so I’m going to go clear my screen and go and edit my file. All right, let’s take a look and see what I did here. I misspelled the claim name. So it should be inventory, not inventory. Oh, I can see I also have another typo here, which is claimed.

I just noticed I also have mounts misspelled here as well. So it needs to be mounted. Hopefully this is it, kubectl apply ‑f and then the name of the file we’ll be working with. I’ll go clear my screen and if I do a kubectl get all, now our pod is stuck in a pending state. We need to find out why it’s not working.

So if we do a kubectl describe and po and then the name of the pod here. Okay, we can see that it’s waiting for the persistent volume claim. So this means I probably just missed that. So if I go and clear. Go and edit my manifest file.

This time, I’m just going to go and copy it just to make sure I didn’t misspell anything. Come back down to my container definition and going to just remove this and paste in the name of the persistent volume claim and pray that it works. I’m going to do another kubectl apply ‑f and inventory‑mongodb‑depl.yml. All right. Now I’m going to execute another kubectl get po, and we have container creating this time.

And if I do another one, let’s see where we’re at. All right, we have one running. So that was just it. And if I go and describe the container, so kubectl describe po and then the name of the pod that we have, we should be able to see that we have a mount in here. Okay, if I go and scroll up, we should have right here under Volumes inventory‑mongo‑storage, Type: PersistentVolumeClaim.

And then we have a claim name, read‑only false, which means that obviously you can write. Now if we come back over to the Amazon console and I just come back over here and just click on Volumes. And all the way down here, we have our gp2, which is 5 GB. And this right here is the volume that our MongoDB instance is now using. Okay, it’s official.

We are now using EBS volumes with our Kubernetes cluster. Everything checks out. Of course, there were just a few issues that I had to go and work through. But other than that, things should work for you out of the box as long as you don’t have any typos like I do. All right, that’s all I have.

I am Travis Thomsen, and I will see you in the next one..

Code Examples

# Installation du driver EBS CSI
kubectl apply -k "github.com/kubernetes-sigs/aws-ebs-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.28"
# storage-class.yml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp2
reclaimPolicy: Retain
---
# persistent-volume-claim.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: inventory-mongo-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ebs-sc
  resources:
    requests:
      storage: 5Gi

Demo: Deploying RabbitMQ

Hello again, I’m Travis Thomsen. In this demo, we’re going to go and deploy our RabbitMQ backing service. Okay. Because we are dealing with microservices and we want to have communication going back and forth between our various microservices, we need to go and deploy out RabbitMQ. So we’re going to be working with operators, and operators are nothing more than just a piece of software that adds some additional functionality to Kubernetes.

What this allows us to do is go and deploy out RabbitMQ without having to go in and write up an entire manifest file for deployment. Now, we do still need to create a manifest file, but it’s going to be much more simplified than what we did with MongoDB. Okay. So after we go and install our operator and get things working, we’re going to go and create our file, and then go and deploy it to EKS, so let’s go and get started. Now, in order to use the operator, I need to go and install it, and to do that, we’re just going to be executing a kubectl apply ‑f, and another thing we can do when it comes to supplying a manifest file is we can supply one from a URL, and that’s what we’re going to be doing here.

So this is going to go and install the operator for us. Hey, everything checks out. I’m going to clear my screen. What I can do is do is kubectl get all and go and supply a namespace and that namespace is going to be RabbitMQ ‑system. Okay.

So we’re going to see everything related to the operator that we just went and deployed out. Now that we had the operator installed, what we can do is go and create a manifest file. Like I said, this is not going to be a deployment, it’s going to be a lot simpler than what we’ve done previously. So I’m going to go and navigate to my manifest files and then create a new manifest. That’s going to be rabbitmq.yml.

Alright, so let’s go and create a file, so apiversion. This time, our API version is going to be rather unique. We what need to do is supply rabbitmq.com/v1 and then beta. Okay. So that is the API version we’re using.

Again, we’re referencing what we installed using the operator, and then we have another kind, and this is going to be again, a kind that is supplied by the operator, and it’s going to be Rabbitmq and then Cluster. Okay. Next is our metadata. Next, when you go and supply the name of our RabbitMQ cluster, so name, and then I’m going to call it rabbitmq, and I’m just going to use srv. And next, we go and supply our spec.

Now, technically, what I could do is just stop and not supply a spec and it will go and deploy out RabbitMQ for me, but what I do want to do is I want to go and supply the storage. So we need to go and supply our persistent storage, so we’re going to say persistence, and then we have our storageClassName, and when you supply the name of the storage class that we created a few videos ago, so ebs‑sc for storage class, and then we need to go and supply the amount of storage we’re going to be using. Alright, I think this time I’m just going to go with 10 GB, and I just realized that G does need to be capitalized. Okay. We should be good now.

Okay. Now we’re ready to go and deploy our RabbitMQ cluster, so kubectl apply ‑f, the name of the manifest, which is rabbitmq.yml. Okay. It looks like we have an issue here. Okay.

I see what I did wrong here. This is actually supposed to be v1beta1. Everything else looks correct. Okay. Now everything is fine.

So if I do a kubectl get all, you should be able to see that we have our RabbitMQ pod in the process of being created, so this will go and take a bit of time. So if I actually just do get in this time, you can still see that it’s in init, so I’m going to go ahead and pause and just let this run its course. Alright, another couple of minutes have passed. If I do a kubectl get po, you can see that we have our RabbitMQ cluster running. Okay.

Now that we have our two backing services created, we can go and work on deploying out our first microservice. I’m Travis Thomsen, and I’ll see you in the next one..

Code Examples

# Installation de l'opérateur RabbitMQ
kubectl apply -f https://github.com/rabbitmq/cluster-operator/releases/latest/download/cluster-operator.yml

# Vérifier l'installation
kubectl get all -n rabbitmq-system
# rabbitmq.yml
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: rabbitmq
spec:
  replicas: 1
  resources:
    requests:
      cpu: 200m
      memory: 500Mi
    limits:
      cpu: 500m
      memory: 1Gi

Demo: Deploying the Inventory Microservice

Hello again. I’m Travis Thomsen, and now that we have our backing services out of the way, we’re ready to go and deploy out our first microservice, which is going to be the inventory microservice. First thing we need to do is go and create a new deployment file for our inventory microservice. Now, this is the first time we’re going to be working with environment variables with our deployments to Kubernetes. One of the factors of the 12‑Factor app is that we don’t go and store information in a config file.

We use environment variables instead, and that’s what we’re using here. Now, we do have a config file, but it is nothing more than just a mechanism to get our environment variables into the application, so we’ll be going and checking that file out. Now, I am logged into my EC2 instance, and if I do an ls, you can see that we have our code directory, so let’s go and navigate to that directory, and in here, we have bevco inventory, and that is the microservice we’ll be working with first, so go and navigate to that directory. And if I do an ls and we need to navigate into src, and in here is where we have all the code for our microservice. Now, I need to go and take a look at my config.ts file.

In here, I have two environment variables. The first one is going to be the port which we’re running our application on. I’m just going to go ahead and leave it as port 3000. The second environment variable is the most important one which is going to be our database connection string. So we have an environment variable called database and that is what we need to go and set.

So I’m going to go ahead and quit, and I’m going to go ahead and just go back over into manifests. So I need you to go and create a new manifest file, so vi inventory‑depl.yml. So as always, starting off with apiVersion, and because we’re dealing with a deployment, it’s going to be apps/v1, our kind is going to be Deployment. You can go and supply our metadata, and I’m going to go and name this deployment, so we need to go in and name our deployment, and I’m going to call it inventory‑depl. Next, we need to go and define our spec and the number of replicas.

Okay. By default, we’re just going to have one replica. We’re not having more than when we start getting into autoscaling. Next, we need to go and specify our selector, and then the matchLabel, and again, this is going to be a key value pair, and we’re going to call it app and then bevco‑inventory. Alright.

Now let’s go and define our template, and much like before, we need to go and supply our metadata for our matchLabel and then labels, and we need to make sure that we supply app and then bevco inventory. Okay. So after our metadata, we need to go and supply our spec and then containers. We need to go and supply a list of containers, we only have one, and we want to go and name it bevco‑inventory. We also need to supply our image, but this time, we’re going to be pulling from the repository that we created previously.

So if I come over to the AWS console and I go and look for Elastic Container Registry, or ECR, go and click on it, we have a list of our repositories here, and what I’m looking for is going to be tthomsen‑bevco‑inventory. So I want to go and copy this URI, go back over to my code, and I’m going to go and paste that in, and I want to make sure that I end this with :latest. Okay. So that’s our image. Next up, we need to go and supply our environment variables, so env, and again, this is going to be a list of environment variables.

At this moment, for this particular pod, we only have one, which is our database, so dash, so we need to supply the name of the environment variable, and again, because this is all caps, I need to supply it in all caps and it’s going to be DATABASE and then we supply the value. Alright. So this is going to be the connection string for our Mongo database, so it’s going to be mongodb:// and then the name of the service that was created, so, and that was inventory‑srv, and then we need to supply the port number, which is going to be colon and then 27017 and then slash and then the name of the database which is going to be inventory. Alright. That’s everything for the deployment.

Now, let’s go and create the service, and the way we do that is that we use the three dashes and now we can supply another YAML file, so apiVersion, and because this is a service, we just do v1 and then our kind is going to be Service. You’re going to supply the metadata. This is where we go and name the service, and it’s going to be bevco and then ‑inventory and then ‑srv. Now I want to go and create the spec for our service, and we need to go and supply our selector. This way we’re able to go and find our pod, and this needs to go and match app and then bevco‑inventory.

Alright. It looks like everything matches up. Up next is going to be our ports, we only have one, and again we need to supply a list so start with the dash and then the name, and I’m just going to call this bevco‑inventory. Next is going to be the protocol. This is going to be TCP and then our port, and I already know it’s defaulted to 3000, and then the target port, which is also going to be 3000.

Okay. We should be able to save and quit and apply our manifest. So kubectl apply ‑f and then the name of the manifest file, which is inventory‑depl.yml. It looks like I have a typo somewhere, so I’m going to go back and edit that inventory‑depl file. I go up to the very top.

Let’s take a look here. Okay. So it looks like I misspelled metadata, go figure. I’m just going to double‑check and make sure I don’t have any other spelling errors. Okay.

Not that I can tell, but I guess we’ll see when we run it again. So kubeCTL apply ‑f and then the name of the file. Okay. Everything checks out this time. So we can do a kubectl get pod, and we have our microservice running now.

Now that we’ve gone and deployed on our microservice, how do we know that it’s actually functioning right? Well, we can go and check the logs on it. So I’m going to go and execute a kubectl logs and go and grab the name of the microservice, which is right here. As you can see, we are getting an error, and it looks like it’s related to MongoDB, so let me go clear my screen, go and edit that manifest, and sure enough, right here, you can see that I don’t have ‑mongo, so I’m basically just referring to its own service which is obviously not going to work. Alright. That should fix the issue.

I’m going to do another redeploy, so kubectl apply, and then the name of the manifest file, which is going to be inventory‑depl. Okay. So now we can go and go get a list of our pods, so kubectl get po. As you can see, we have one running and one is in the process of being terminated, so I’m going to go and inspect the logs again. I’m going to grab the name of the new pod here, and as you can see, we no longer have that error, which means that we have connected to our Mongo database.

Now, currently, we are not able to go and access the microservice. We will be able to do that once we get the API Gateway working. Coming up in the next demo, we’re going to go and deploy out our microservice for dealing with messages to the inventory system. I’m Travis Thomsen, and I’ll see you in the next one..

Code Examples

# inventory-depl.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bevco-inventory-depl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: bevco-inventory
  template:
    metadata:
      labels:
        app: bevco-inventory
    spec:
      containers:
        - name: bevco-inventory
          image: <ecr-uri>/bevco-inventory:latest
          ports:
            - containerPort: 3000
          env:
            - name: PORT
              value: "3000"
            - name: DATABASE
              value: "mongodb://inventory-mongodb-svc:27017/bevco"
---
apiVersion: v1
kind: Service
metadata:
  name: bevco-inventory-svc
spec:
  selector:
    app: bevco-inventory
  ports:
    - protocol: TCP
      port: 3000
      targetPort: 3000

Demo: Deploying the Inventory Messaging Microservice

Hello again. I’m Travis Thomsen. In this demo, we’re going to start working with the inventory messaging microservice. Initially, I thought about making it a part of the inventory microservice, but I decided against it. And then I thought about making it a companion container for it and promptly decided against it as well, so it evolved into its own thing.

So for this round, we’re only going to be going and creating a deployment file for it. The only thing that this service talks to is RabbitMQ and then the database for the inventory system. Okay. So let’s go and get to work. I’m already logged into my AWS instance.

If I do an ls, we want to go and navigate into the code directory, and we want to take a look at the inventory messaging system, so go and CD into bevco‑inventory and then messaging. If I do an ls, I’m going to go and navigate into the source directory and here we have our config.ts file. Let’s go and open that up and take a look at it. Alright, we have quite a few environment variables, some of them we’re not going to be able to implement in this demo and that will be happening in the next one when we start talking about secrets. But like the previous one, we do have a database environment variable.

We also have the URL for RabbitMQ. By default, we’re saying localhost, we will be overwriting that, and then we have the RabbitMQ user and password, which we need to go and grab from our secrets, but we’ll be worrying about that later. And also we have another one which is going to be our inventory queue, and by default, we’re setting that to InventoryUpdateQueue. So in a nutshell, what this microservice is responsible for is that, again, we’re simulating going and ordering beverages for a restaurant, and obviously, there’s a whole supply chain element to it, which is not going to be a part of this microservice. We’re just going to go and simulate it.

So what we’re doing is that we have another API microservice for restocking, so when the restaurant receives the order, they’re able to go and restock, and what the restock microservice does is it tells it how many new beverages we’re going to be adding to that particular inventory item, and then inventory messaging is going to go and pick that up and update the quantity within our inventory microservice.

Okay. So let’s go and exit out of here and go drop‑down one more level, and we need to go and navigate into manifest. So let’s go and create a new manifest file. So I want to call this one inventory and then messaging‑depl and then yml. Alright, so we’ll start off with apiVersion, and because we’re working with a deployment, it’s going to be apps/v1 and our kind is going to be Deployment, and then we need to supply our metadata, make sure I spell it right this time.

The name of our deployment is going to be bevco‑inventory‑messaging and ‑depl. Next comes our spec. We’re going to have one replica, and then we need to go and supply our selector. So we’re going to have our matchLabels. So our matchLabels is going to be a key value pair and I call this app and then bevco‑inventory‑messaging.

Now we go and define out our template. We want to go and make sure that we are able to go and use our match label, so we have our metadata, and I want to make sure I spell metadata right, and then labels. And just like above, we have app and I don’t want to risk missingpelling it, so I’m just going to go and copy what we have here, and we supply the spec for our template and our containers, and remember, containers takes a list, so we start off with a dash and then name, I call this bevco‑inventory and ‑messaging. Okay. Let’s go and set up our image.

I’m already on the page for my Elastic Container Registry, and I’m going to look for bevco‑inventory‑messaging, so I’m going to go and copy that URI. Go back over to my code and just paste that in, and we want to make sure that we use :latest. Alright. So let’s go and supply our environment variables, so env, and again, this is going to be a list, so dash and we supply the name of our first environment variable which is going to be DATABASE, and I come down and I want to make sure I supply the value, and I’m just going to go and paste in my value here, so we’re using mongodb://, and then we’re supplying the service for the MongoDB inventory service, which is inventory‑mongo‑srv, and then we need to supply the port, so:27017/inventory.

We have another environment variable we need to go and set up. This time, it’s going to be the RabbitMQ URL. So again, this is going to be in all caps RABBITMQ and then _URL, and then we’re going to go and supply the value for that, which is going to be the name of the RabbitMQ cluster, which is rabbitmq and then ‑srv. And finally, we have one more we’re going to be dealing with before we start talking about secrets. So we need to go and supply the RabbitMQ inventory queue, so RABBITMQ_INVENTORY_QUEUE, and the value is going to be UpdateStock.

Okay. So this is what we’re going to call it. We’re not going to go and deploy out our manifest just yet, mainly because we need to start talking about secrets, which we’ll be doing in the next demo. So I’m Travis Thomsen, and I’ll see you in the next one..

Demo: Working with Secrets

Hello again. I’m Travis Thomsen, and in this demo, we’re going to start working with secrets. So what exactly are secrets? Well, it’s kind of obvious, right? It’s really just data that we want to make sure that is kept private. This is anything from like username, passwords, and API keys. The main thing we want to make sure is that we’re not storing this data in our pod definition and it is being kept somewhere else and where it’s being stored is in etcd.

The big thing that you need to be aware about secrets is that they are Base64 encoded. If you know anything about anything that is Base64 encoded, it means it can be decoded, therefore, this data is not encrypted by default. Now, we do have the ability to go and encrypt it at rest, but that is actually out of the scope of this course. So let’s go and take a look at what a secret file looks like. Again, with anything that we do when it comes to these manifest files, we have an API version, and that is going to be the one.

The kind is going to be secret, and then we have metadata, and we’re going to be supplying the name for our secret. Now, one thing that we can do is that we have the ability to go supply multiple secrets, and the way we do this is by supplying string data. Now, if you don’t supply string data, you’re going to have to go and Base64 encode your secret yourself, but because we have string data supplied when we go and apply our secret, it will go and Base64 encode everything for us. So here, we have a key value pair, we have username, and we’re supplying the username, which I’m just calling username, and then we have another one which is password, and the value is going to be password. Now, username and password will be Base64 encoded when we go and create the secret.

Okay. So how do we use our secrets in our pod definition? If we come all the way down to our environment variables, you can see that we have a name, and again, it’s going to be username, and depending on our code, it’s going to be all caps or it can be lowercase, in this instance, we’re using all caps, and then under that, we have valueFrom, and the way we do this is we supply secretKeyRef, and then under name, we have secret‑data, and when I go back, you can see that we’re using what is defined in our metadata right here, and then we have the key which we’re going to be using which is going to be username.

So this will go and grab the username from our secrets. Okay. So let’s go and head into our demo. Now, the first thing we’re going to do is just, for demonstration purposes, we’re going to go and add a secret, that way you know how to go and do this, and then I’ll show you how to go and grab a secret and decode it just at the command line, and then ultimately, we want to go make sure that we add our secrets for RabbitMQ to the manifest file for our messaging queue. Okay.

So let’s go and jump into it. So let’s go and start things off by going and creating a secret. I’m going to go and CD into my manifest directory. I’m going to go and create a new file called secrets. Start off by supplying my apiVersion, and that is going to be version 1, and our kind is going to be a secret.

Just like with everything else, I have my metadata, and I’m going to go and supply a name. I’m just going to call this top‑secret. Because we’re going to be supplying string data, we need to go and specify that we are using string data, so stringData and then I’m going to supply a username and this user is going to be admin and then we’re also supplying a password, and I’m going to go and copy and paste this in because it is a super long password, not really, but it’s a lot easier than typing everything out, and let’s go and save and quit.

Now, what I can do is a kubectl apply just like everything else we’ve been doing, and then I supply the secrets file. Okay. So top‑secret has been created, let’s go and access it. I’m going to go and paste this command in. We’re going to go and set a variable, so I want to set username equal to, and this is going to be in quotes, it’s going to be $, in parentheses, kubectl get secret, and we go and supply the name of the secret, which is top‑secret, and then we want to make sure that we get the specific secret that we created, which is going to be our username, so we use ‑0 and then jsonpath, we’re going to set that to equal, and again in single quotes here and curly braces .data.username, and we’re going to go and pipe this to Base64 and use the flag ‑‑decode, and this is going to go and grab our secret, and because it’s Base64 encoded, we’re to go and decode it into plain text.

Now I can go and echo that out, so $username, and as you can see, we have admin here, and we could do the exact same thing here for our password. All I have to do is just go and change this, the password, and obviously, I want to go and change what I’m saving it to as well, so let’s get rid of that. Alright. Now, I should be able to go and just echo out password, and there you go. And like I said previously, because this is not encrypted, this is just a way of obfuscating your secrets, and again, we do have the ability to go and encrypt them at rest, which we are not going to do because that’s out of the scope of this course.

And now we’re able to do the exact same thing here with the username and password that was created for RabbitMQ. So I’m going to go and paste this in. We’re going to be doing the exact same thing here, but this time we’re grabbing the rabbitmq‑srv‑default‑user, and again, we are supplying the data path which is data.user, and we’re going to go and decode it. And as you can see here, we have the default user which is just really just a bunch of random characters, and we could do the exact same thing for the password as well. So we’re going to go right‑click and paste that in, and as you can see, we now have our password for RabbitMQ.

And this is all generated randomly when we go and deploy out our RabbitMQ cluster. So now, let’s go and update our messaging service so we can go and access RabbitMQ. So execute vi and then inventory and then messaging. So I’m going to come down, so down here at the very bottom, I’m going to add a new line and supply my name for my next variable. That variable is going to be RABBITMQ_USER.

Now we are not supplying a value, we’re supplying valueFrom, and that valueFrom is going to be a secret key reference, so type secretKey and then Ref. So now I go and supply the name of my reference and that is going to be rabbitmq‑srv‑default‑user, and we go and supply our key and that is going to be a username. Alright. So we’re ready to go and supply our next value, and this is going to be RABBITMQ_PASSWORD, and just like how we did with the username, it’s going to be valueFrom and we have our secretKeyRef. Again, we’re going to be using the name, which is going to be rabbitmq‑srv‑default‑user, and then our key is going to be password.

Alright. It looks like I’ve got a typo here, let me get that fixed real quick. Okay. RabbitMQ. Yep, looks right.

Alright, let’s try this out. Alright. So we’re going to execute a kubectl apply ‑f and then the name of our manifest file, which is going to be inventory‑messaging‑depl. Okay. Okay, so let’s do a kubectl get po.

Okay. We can see that our messaging service is running. I could do a kubectl logs just to make sure everything is working right, and we don’t have any errors, so everything looks good. We now have our inventory messaging service deployed out, it’s using secrets. Now, we can move on to our next step, which is going to be going and deploying our restock microservice.

I’m Travis Thomsen, and I’ll see you in the next one..

Code Examples

# secrets.yml
apiVersion: v1
kind: Secret
metadata:
  name: rabbitmq-secret
stringData:
  username: guest
  password: guest
# Utilisation des secrets dans un pod
env:
  - name: RABBITMQ_USER
    valueFrom:
      secretKeyRef:
        name: rabbitmq-secret
        key: username
  - name: RABBITMQ_PASS
    valueFrom:
      secretKeyRef:
        name: rabbitmq-secret
        key: password

Demo: Deploying the Restock Microservice

Hello again. I’m Travis Thomsen, and in this demo, we’re going to start deploying out everything for our restock microservice, so let’s jump into it. So what exactly does that entail? Well, everything that we’ve kind of done previously. However, this time, we’re going to be deploying out both our MongoDB database, as well as the restock microservice itself, so we’re going to be creating two deployment files. Because our restock microservice is going to be communicating with the MongoDB, we need to go and make sure that we configure everything to be able to communicate, so we’ll be setting up our environment variables for Mongo DB, and because we’ll be using RabbitMQ as one of our backing services, we also need to include the connection info as well.

We’ll also be creating services for MongoDB, as well as our restock microservice, so let’s go and jump into it. Now, I’m already logged into my AWS instance, and I go and navigate into my manifest directory, and if I do an ls. Now, the first thing we need to do is go and get our MongoDB database deployed out. Now, I’m going to start off by going and just making a copy of the one we created for the inventory system, except this time, I’m going to call it restock‑mongodb and ‑depl.yml. Okay.

Let’s go and edit that file. Now, what I’m going to do here is I’m going to do a search and replace, so we’re going to do %s/ and then inventory/restock and then /g, and I see that I have an error at the top. I mean, just really, it’s just a typo, but I can just go and change this to restock, go and write and quit and we should be good to go. Now, I’ll just do a kubectl apply ‑f and then restock mongo.depl. Let’s do a kubectl get in just to see where things are at.

Okay. You can see that our container is creating, and if I do get pvc, as you can see, we have three persistent volume claims. We have one for our RabbitMQ server and one for the inventory MongoDB system, and then now we have the one for the restock. Now hopefully by now that pod should be done, it is, and we can do a kubectl logs and just see what’s going on with that pod. Alright.

Everything looks good. I don’t see any errors. Now we’re ready to go and work on the restock microservice, so vi restock‑depl. We’ll go and start off by specifying our API version, and that’s going to be apps/v1. Next, we need to supply our kind, which is going to be Deployment, the metadata, and we’re going to go and name this bevco‑restock‑depl.

Let me go and supply the spec. We’re going to have one replica, so replicas. Let’s set that to 1 and go and supply our selector, and that is going to be matchlabels. I’m going to go and supply our key value pair which is going to be app and then bevco‑restock. Now we need our template, and just like above, we have our metadata, and we need to make sure that we supply our labels here, and just like above, we have app and then bevco and ‑restock.

Next comes the spec, and we’re going to go and define our containers, and remember, containers take a list of containers, but we’re only going to be supplying one and that is going to be bevco‑restock, And now for the image, Okay, I’m going to head over to the AWS console and I need to go and grab my image here, and this is going to be the restock one, so I’m going to go and copy a clipboard and just paste that in, and we make sure that we’re using latest, so:latest.

Okay. Now it’s time to supply our environment variables, so we do env: and start on a new line, and remember, this also takes a list of environment variables, so I’m using dash and then a name. We’re going to go and name our environment variable, which is going to be database, and then we need to go and supply the value, and I’m just going to go and paste this in. Now it’s time for our next environment variable, and this is going to be the RabbitMQ URL, so RABBITMQ_URL. We’ll be supplying the value, and that value is going to be the name of the service, which is rabbitmq‑srv.

Now we need to go and supply the name of the queue. This is going to be RABBITMQ_INVENTORY and then QUEUE, and the value of that queue is going to be UpdateStock. Okay. Now we need the RabbitMQ user, so name: again, this is all caps and we have RABBITMQ_USER. Okay.

So now we need to go and supply our value, which is going to be valueFrom, and that’s going to be secretKey and Ref. Next is the name, and I’m going to go and paste this in because I might typo it, and that’s going to be rabbit‑srv‑default‑user, and then we have our key and that is going to be username. Okay. Now we need to repeat the exact same thing, but this time for the RabbitMQ password. So we’re going to supply a name and then all caps RABBITMQ_PASSWORD and then valueFrom, and that valueFrom is going to be our secretKeyRef.

We need to supply the name of the speaker we’ll be working with, and that is going to be the rabbitmq‑srv‑default‑user and then our key is going to be password. Okay. Now that completes our deployment. Let’s go and set up our service. So next, supply the three dashes and then apiVersion, and that version is going to be v1, again, it’s because we’re dealing with the service.

The kind is going to be Service. And next is our metadata, go and name the service, and we’re going to call it bevco‑restock‑srv. Next is our spec, and we go and supply our selector, and our selector is going to be a key value pair which is going to be app bevco‑restock. And finally, we have our ports, and this is also going to be a list, so name and call it bevco‑ and restock. For my protocol, it’s going to be TCP, and my port is going to be 3000.

And then finally, we have the target port which is also going to be 3000. Alright. That wraps everything up. Okay. Let me check some things here, and it looks like I do, it looks like I have a spelling error here and obviously that will cause a problem when we go and deploy, so let me get those situated.

Okay. And it looks like I have, okay, and it looks like I do have one more spelling issue right here. Let’s get that situated, and I don’t have my L capitalized. I think that will do it. Okay.

Let’s go and give this a shot, so I’m executing another kubectl‑apply‑f and then the name of the manifest, which is going to be restock‑depl. Okay. Everything checks out. Let’s do a kubectl get po. It looks like the restock microservice is in business.

Now, let’s go and check the logs just to make sure everything is fine. So kubectl logs and the name of the pod and everything checks out. We are good to go. Okay. So at this point, we have one more component we need to go and deploy out and that is going to be our API Gateway, which is going to be the front end to our microservices.

So that’s it for this demo. I’m Travis Thomsen, and I’ll see you in the next one..

Demo: Deploying API Gateway

Hello again. I’m Travis Thomsen, and in this demo, I want to go and start working on our API Gateway. This way, we have the ability to go and make our microservices available publicly. Just like what the other microservices, we’re going to be creating a deployment file for our API Gateway. Now, we have a couple of environment variables for this, and mainly, it’s just the endpoints for our microservices.

Now, things are going to be a little bit different this time though when it comes to our service. Because we want this publicly available, we’re going to be creating a load balancer service. Now, what this is going to do is it’s going to go and work with Amazon and provision out a load balancer which will go and sit in front of our application and route traffic to it. Okay. So let’s get started.

Okay, so let’s start by going and inspecting our codes. So let me go into the code directory, go into the api‑gateway directory, and then src. In here, we have a config file. As you can see, we have three environment variables, again, we’re going to ignore port, we’re going to leave it on port 3000, and we need to supply the endpoint for our inventory, as well as the restock, so we have INVENTORY_URL and RESTOCK_URL. Go and save and quit.

Alright. So now we’re going to go back to our home directory and go into the manifest directory. I want to go and create a new file and that is going to be api‑gateway‑depl, and then .yml. The first thing I do is supply my apiVersion, and because we’re working with a deployment, it’s going to be apps/v1. The kind is going to be Deployment, followed by my metadata.

We can go and name our deployment, bevco‑api‑gateway. Next, we need to supply our spec and the number of replicas, which is going to be 1 and then the selector. Next comes the matchLabel, I’m going to call it app and then api‑gateway. Okay. After our selector comes our template, and again, we need to go and set our matchLabel, so this is going to go under metadata and then labels, and just like what we have above, we have app and then api-gateway.

After our metadata comes the spec, and this is where we go in separate containers. Again, containers take a list, so dash, we’re going to go and name our container, we’re going to call it bevco‑api‑gateway. Next is the image, and we need to go over to our Container Registry and grab the API Gateway, which is right here at the top, go and paste that in, and we need to make sure that we’re using latest, so:latest. And now we need to set up our environment variables, which is going to be env, and this is also going to be a list of environment variables, so dash and then name, and I’m going to call this INVENTORY_URL. This is basically what we have in our config file.

So now we need to go and supply the URL for the microservice, so we start off with value and then http:// and then the name of the service for our inventory microservice, which is going to be bevco‑inventory, and then srv, and then we make sure that we supply the port, which is going to be port 3000. Okay. So we have one more endpoint we need to go and supply, and this is going to be for the restock URL, so RESTOCK_URL and then we supply the value and that’s going to be http:// and then bevco and then restock‑srv and then port 3000. That finishes everything off here, and now we can go and work on the service, and because we’re using multiple YML files within one, we need to make sure that we go and separate it using three dashes and then we supply the API version, and that API version is going to be v1, next is the kind, which is going to be Service, the metadata, and then the name of the service and this is going to be bevco‑api and then srv, and then the spec and the first thing we supply in our spec is our selector, and that’s going to be app and then api‑gateway.

And remember, this needs to match exactly what we defined in our template metadata labels. After the selector, we go and define our ports, and ports will go and take a list of ports, and we start off with the name and that name is going to be api‑gateway. Next is the protocol and that’s going to be TCP and we go and supply our port, which is going to be port 80, and then the target port, and this is going to be port 3000. Finally, we’re to go and supply our type. We’re not going to be using ClusterIP this time.

We’re going to be using LoadBalancer. So when we go and apply this manifest, it’s going to go and create a load balancer in AWS and then it’s going to go and route traffic to our service and ultimately to our pod. Just notice a typo here. Obviously, if TCP is not spelled correctly, it’s going to cause an issue and misspelling the name is not a big deal, but it does need to be fixed anyway. So let’s go and save and quit.

Now let’s go and apply our manifest, so kubectl apply ‑f and the name of our manifest which is api‑gateway‑depl. Now, if we do a kubectl get po, a list of our pods here, okay, we see that we do have the bevco‑api‑gateway running. Let’s go and take a look at the services. Okay. So right here, you see that we have our load balancer.

Now, the way we can go and access it is going to be copying this URL here, and what I can do is go and open up a browser tab, pop this in, and do /api and then inventory. Now, if you don’t get anything back immediately, don’t freak out. It’s going to take a little bit of time to get this load balancer provisioned out. So, what I’m going to do is I’m going to go and pause and we’ll resume once everything is up and running. Alright, as you can see, everything is coming back.

Currently, we don’t have anything in our database as yet, so we’re just going to get an empty array coming back from our inventory, which means that things are now functioning. So, congratulations. We now have all of our microservices deployed out to Kubernetes. The next thing we’re going to do is we’re going to go and load up some data into our application and just test things out. I’m Travis Thomsen, and I will see you in the next one..

Code Examples

# api-gateway-depl.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bevco-api-gateway-depl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api-gateway
  template:
    metadata:
      labels:
        app: api-gateway
    spec:
      containers:
        - name: bevco-api-gateway
          image: <ecr-uri>/bevco-api-gateway:latest
          ports:
            - containerPort: 3000
          env:
            - name: INVENTORY_URL
              value: "http://bevco-inventory-svc:3000"
            - name: RESTOCK_URL
              value: "http://bevco-restock-svc:3000"
---
apiVersion: v1
kind: Service
metadata:
  name: bevco-api-gateway-svc
spec:
  selector:
    app: api-gateway
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000

Demo: Testing the Deployment

Hello again. I’m Travis Thomsen. So now that we have all of our microservices deployed out, we need to make sure that everything is functioning properly. So to do that, we’re going to go and test it. So we’re going to be using an application called Postman to go and access our APIs.

What this allows us to do is perform any kind of CRUD operations against our APIs. Specifically, we’re going to be working with the POST and PUT. If we’re just doing GET, we can go and access it through the browser. Then we’re going to go ahead and bulk load some data. This is going to be our test data so we can go and test out a reorder, and the way we do that is that we’re going to place an order, this is going to simulate a real world reorder, so that order gets put into the system, and then after shipping, we’re going to do a PUT to tell the Restock app to go and update the inventory for one of our beverages.

Okay. So let’s go and jump into it. Now we’re going to be using Postman to go and access and test our APIs. What’s nice about it is allows us to go and execute CRUD commands, that’s create, read update, delete, very similar to how you do this with Curl, but instead it’s just an application that does it for you. It supports a wide variety of operating systems, Windows, Mac, as well as Linux, and all you need to do to get started is just to go and download it, install it, and you’re pretty much ready to go.

All the data and URL endpoints can be found in the GitHub repository. Just go to Section07 and look for S07L08, and as you can see here, it has the endpoints we’re going to be accessing along with the data. Now, in order to go and access our endpoints, we need to go and get the publicly accessible FQDN for our service. So execute a kubectl, get svc, and here we have the endpoint for our load balancer. Let me go and copy that, and then I’m going to come over here to Postman.

I go and paste this in and go and set this to post, and we go and grab the endpoint right here, which is going to be api/inventory and bulkload, and then it’s going to go and paste that in. Okay. I’m going to come back over here to Body, I’m going to select raw and then JSON. Let me go and grab my data here. I’m just going to go and copy it, and then paste it in.

Now we just go and click Submit. We don’t have any errors, and as you can see here, we have a 201 Created, which means that everything worked just fine. We can come over here and grab this real quick. Open up a new tab, paste this in, and I’m just going to go and remove bulkload, and we’re going to do a get, and we should get back all of our inventory data. Okay.

There we go. And the one we’re going to be working with is going to be Bob’s Root Beer because it has a quantity of 0. So then I come back up, add a new tab, paste in my URL. I want to go and change out our endpoint. So the next endpoint we’re working with is going to be restock, so let me go and grab that, and I’m going to go and replace inventory with restock, and then come over here to Body, and again, select raw and then JSON.

I’m going to go and grab my data, paste it in, and we need to go and replace the inventory ID, so I’ll come back over here to GET and so I’m going to grab the inventory ID for Bob’s Root Beer, go and replace that, paste it in, and we need to go and set this to POST. Okay. And now we have our restock ID. I’m going to come back over here, I’m going to go and grab the load balancing endpoint, create a new tab, paste this in. This time, we’re going to be doing a PUT.

Coming back over here to the instructions, we have the api/restock, the ID, and then updatestock. So I’m going to go and grab this, go and paste that in, you need to go and grab the ID for restock, which is right here, and now we’re going to go and replace this right here. Now, just go and click Send. Okay. So now we do get a response back, and if I come back over here to GET and I click Send and I scroll down, we do have it in inventory of 100 now for Bob’s Root Beer, which means that our microservices are working properly.

Alright, we now have our microservices working. We tested them out, everything is good to go, and this will go and complete the module. Coming up next, we’re going to start working on how we can go and scale out our microservices. I’m Travis Thomsen, and I’ll see you in the next one..

Code Examples

# Exemple de Deployment Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server-depl
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-server
  template:
    metadata:
      labels:
        app: web-server
    spec:
      containers:
        - name: web-server
          image: nginx:latest
          ports:
            - containerPort: 80

8. Scaling Your Node.JS Microservice in EKS

Demo: Requests And Limits

Hello, again, I’m Travis Thomsen. So, one of the nice things about Kubernetes is that we’re able to go and do some resource management for both our pods and containers. And this is where requests and limits come in. When we go and create our pod definition, we can specify a request for the amount of resources that we want for our container. These are things like CPU, memory, as well as Hugepages if you’re using Linux.

So what we’re defining is the bare‑minimum resources that we want for our container, which means that our container does have the ability to go and access more resources than what was requested. And the way all this works is that the kube‑scheduler is going to go and take a look at what is being requested and then determine what node to go and place that pod based off of available resources. And then the kubelet is going to go and enforce that reservation. Okay, let’s talk about limits. Limits are a way of ensuring that our containers don’t go and consume more resources than they should.

So the way it works is that the kubelet is going to go and enforce the limit that is defined within our pod definition, and then the container is not able to go and exceed those resources that have been defined. And if the container tries to go and exceed those limits, one of two things is going to happen, the limit is going to go and retroactively block it from consuming more resources or it’s going to go and forcefully terminate the pod. When it comes to the CPU resources, there’s a few things that we need to be aware of. CPU is going to be measured in CPU units, and one CPU unit is going to equal either one physical or virtual core. When we go and define our CPU, what we’re going to be using is milicores; 0.1 CPU units is going to equal 100 millcores.

When we go and declare our requests, we’re going to go and place them under our pod definition. So we’re going to go and create a resource. And under resource, we have requests, and that’s where we’re able to go and define the amount of memory that we want to have along with our CPU. Now, when we go and define our memory resource, we can do it in one of two ways. We can use either megabytes, which is just an M, or mebibyte, which is Mi.

Now, the difference is that megabytes is going to be 1000 KB, and mebibytes is going to be 1024 KB. And the way we define our limits is going to be the exact same way we go and define our requests. It’s going to be placed into the pod definition. And under resources, we have limits. That’s where we’re going to go and define our memory, as well as our CPU.

Okay, so let’s go and jump into our demo. So we’re going to start working with request and limits. So what we’re going to do is go and modify our inventory microservice, and we’re going to go and add in our request and limits. Then, we’re going to go and redeploy out our manifest, which is going to go and update the Inventory pod. Okay, let’s do it.

I’m logged into my system. I’m going to do an ls. I’m going to go and navigate over to the manifests directory. And the file I want to go and modify is going to be the inventory‑depl file. All right, so I want to come down to the bottom of our deployment definition here, and then go and add a new line.

And the resources are going to be right in line with the name, image, and env. So I’m going to go and start things off by going and declaring our resources. And next, we supply our requests. Under requests is where we’re going to go and request our memory in CPU. So the first thing we’ll do is memory, and I’m going to do 128, and then Mi.

Remember, when we use i, it’s to the power of two. Next is going to be CPU, and I’m going to use 50 milicores. Now, we’re going to go and define our limits. And we’re going to be doing the exact same thing, so memory, and we’ll cap that out at 512. And then we’re going to go and cap our CPU out at 75 milicores.

All right, let’s go ahead and save and quit. So I’m going to do a kubectl apply ‑f, and then the name of the file, which is inventory‑depl. We do a kubectl, and then get po. Okay, you can see that we have our old pod terminating and a new one has spun up in its place, let’s go and take a look at that. So kubectl describe, and then po and the name of the pod.

Let me go and grab that. So when we go and take a look at what we have here, we can see that we actually have our definitions here. So we have our Limits with a cpu of 75 milicore. We do have our memory capped out at 512 MB. And then we also have Requests right here.

Again, our CPU is 50 millicore, and then our memory is 128 MB. Okay, so far, super simple. Now we’re ready to start working with the horizontal pod autoscaler. I’m Travis Thomsen, and I will see you in the next one..

Code Examples

# Exemple de requests et limits dans un pod
spec:
  containers:
    - name: bevco-inventory
      image: <ecr-uri>/bevco-inventory:latest
      resources:
        requests:
          memory: "64Mi"
          cpu: "250m"
        limits:
          memory: "128Mi"
          cpu: "500m"

Demo: Scaling in Kubernetes

Hello again, I’m Travis Thomsen. And in this demo, we’re going to start working with autoscaling. Now, there’s several ways we can handle scaling, and the first one is vertical scaling, and sometimes it’s referred to as scaling up. In vertical scaling, all we’re doing is increasing the resources on an existing system. This includes CPU, as well as memory.

Now, I want to point out that, in reality, when we deal with vertical scaling with our Kubernetes cluster and our pods, what we want to do is we want to go and scale up our worker nodes, and not necessarily the pods themselves. By default, we know that when we go and assign resources to a container within a pod, it can consume more resources. However, we can put a governor in place, which is our limit, and we can tell it not to go and exceed that limit. Now, there are third‑party plugins that technically allow you to go and vertically scale, and all that does is it goes and increases the limit that is assigned to your containers. But that’s not what we’re going to worry about here.

We want to focus on vertical scaling of our worker nodes and not necessarily our pods. So the second way of scaling is horizontal scaling, and this is what we’re focused on with our pods. And the way this works is that when we have an increased demand on our API or our microservice, it’s going to go and scale out more pods to go and meet that demand. And then it will go and kill them off as demand dies down. As we previously discussed, we don’t have the ability to go and exceed the resource limit.

What we’re going to have to do is put a mechanism in place that once we hit like a certain percentage of either CPU use or memory use, it’s going to go and trigger that horizontal scaling event. And the way we do this is by using a horizontal pod autoscaler, sometimes referred to as an HPA. Now within our HPA, we have the ability to go and define the minimum number of pods we want in our cluster, as well as the maximum amount, and then some sort of event that will cause it to go on scale, so like a percentage of CPU utilization. Once it exceeds that target, it will begin the process of going and scaling out. The way that autoscaling works within Kubernetes is that we have a control loop that, by default, is set to every 15 seconds, and this interval is set using the horizontal‑pod‑autoscaling‑sync‑period flag.

The control manager is going to go and query the resource utilization against the metrics that have been defined within the HPA. It’s then going to go and select the pod based off of the selector, and then it’s going to go and obtain the metrics for that pod using one of the metrics APIs. So, in this instance, we’re going to be using the Metric Server. So, based off of that utilization, it’s going to determine whether it’s going to go and scale out or not. Now, anything that has the ability to go and support multiple replicas can be autoscaled, such as StatefulSets, as well as ReplicaSets.

However, DaemonSets, which are basically singletons on each individual node cannot be scaled. So here we have a diagram on how horizontal pod autoscaling works. So we have our HPA, and it’s going to go and communicate with a sub‑source within our deployment or ReplicaSet called Scale. And based off of the metrics that are coming back and utilization, it’s going to go and tell the deployment to go and scale up or scale down. Let’s go and take a look at what an HPA file looks like.

We’re going to go start things off by going and defining our apiVersion, which is going to be autoscaling/v1. We also need to go and supply the kind, which is going to be HorizontalPodAutoscaler. Next is going to be our metadata, where we go and define the name of the HPA, which is going to be, for this instance, inventory‑depl. After that, we go and define our spec. And within our spec, we have our scaleTargetRef, and that’s going to go and contain the information of what we want to go and scale up.

So, we supply the API version, which is the apps/v1, and then the kind. Because we’re working with a deployment, we’re going to go and define a Deployment here, and then the name of that Deployment, which is inventory‑depl. Next, we need to go and define our minimum and maximum number of replicas. For this one, we’re going to have a minimum of three and then a maximum of five. Next up, we’re going to go and supply our utilization.

In this instance, we’re going to be working with targetCPUUtilizationPercentage. So once we’ve hit 50% utilization, it’s going to go and begin the scale‑up process. And then once it drops below 50%, it’s going to go and back off the number of replicas. Now it’s time to go and jump into our demo. So we’re going to start working with HPAs.

Now, before we can go and define our HPA, we want to go and install the Metric Server. This is going to go and supply the utilization for our pods, as well as our nodes. But primarily, we’re more interested in what that information is about our pods. So once we have the Metric Server in place, we’re to go and build out an HPA for the inventory microservice. And once that HPA is set up, what we’re going to do is we’re going to use busybox to go and flood requests to the inventory microservice.

This will go and spike the CPU utilization. And after it goes above 50%, it’s going to go and begin autoscaling. When we kill busybox, that load should start dropping. And after a period of time, those additional replicas are going to get terminated. Okay, so let’s go and jump into it.

Before we can start working with horizontal pod autoscaling, we need to go and install the Kube Metric Server first. And we’re going to do this using a remote file, so we’re going to be executing a kubectl apply‑f., and then the URL will be in the GitHub repository for this course. Okay, our Metric Server has been created, so now we need to go and verify that everything has been installed properly. So we’re going to execute a kubectl get po, and then we use a ‑n for namespace, and we’re going to be using the kube‑system namespace. Okay, as you can see, right here we do have our Metric Server, and it is running.

Now we can go interface with the Kube Metric Server. And do that, we can execute a kubectl and then top, and then we can either supply nodes or pod. So let’s just do nodes for right now, let’s see what we get back. As you can see, we get the usage for both the CPU, CPU%, and the MEMORY(bytes), and then the percentage of memory being used. Likewise, we can do the exact same thing with pods, and it supplies the number of milicores and the amount of memory that is assigned to each of the individual pods.

So you can see the current utilization for what we have for inventory‑depl. Right now, it’s only using one milicore, along with only 50 MB of RAM. Okay, so now we’re ready to go and create our HPA file. So I’m going to go and navigate over the manifests. And next, we’re going to go in vi, and we’re going to call this file inventory‑hpa.yml.

So, we’re going to start off with our apiVersion, and this is going to be autoscaling/v1. Next, we have our kind, and this is going to be HorizontalPodAutoscaler. Okay, time for the metadata. We’re going to go and name the HorizontalPodAutoscalar, so name. I’m going to call this inventory‑depl.

Make sure I spell inventory right. Next, we go and define our spec. So we need to go and specify our scale target, so scaleTargetRef. Now we have some stuff we need to go and reference for our deployment. The first thing is going to be the apiVersion, which is going to be apps/v1.

Next is the kind, which is going to be Deployment, and then the name of the Deployment, which is inventory‑depl. Okay, now that we’ve targeted the right deployment, we want to go and supply our minimum and maximum replicas. We’ll start things off with our minimum number of replicas, so minReplicas, and we’ll be setting this to three. And now, we’re going to do our maxReplicas, and we’ll be setting this to five. All right, so for this example, we’re only targeting our CPU usage, so targetCPU, and CPU needs to be capitalized, and then Utilization, and the U does need to be capitalized again, and then Percentage.

And we’re going to be setting that to 50%. So what this means is that once we exceed 50% Utilization, our pod is going to go and scale up. All right, I’m going to go and save and quit, and we can go and apply our manifests file. So we’re to execute a kubectl apply ‑f, and then inventory‑hpa.yml. Now we can do a kubectl get hpa, and you can see that we have a HPA created.

So right now, you can see the name of the HPA, which is inventory‑depl. It’s going to go and reference our Deployment, which is inventory‑depl. And currently, our target usage is going to be unknown/50%. This will change over time. And then, as you can see, we have our MINPODS as three and our MAXPODS of five.

And currently, it has not picked up the replicas yet. But if I rerun the command, we should have three replicas now, as you can see. If I do a kubectl, and then get po, you can see that we now have three of our inventory pods running. So how do we test this to know that horizontal pod autoscaling is working? Well, we can use busybox to go and take care of that for us. Okay, I’ve gone and opened up a second terminal because I want to go and monitor the HPA to see what’s going on.

So go and execute a kubectl get hpa, supply the name of the HPA, which is inventory‑dpl, and then we’re going to use ‑‑watch. So what this is going to do is monitor the HPA. That way, we can see when our replicas begin to grow. And come back over to my first terminal window, and we’re going to be using this command, which is kubectl run ‑i ‑‑tty load‑generator ‑‑rm ‑‑image=busybox:1.28 ‑‑restart=Never ‑‑ /bin/sh ‑c. And then we’re going to pass in a sleep command, so while sleeping.

We’re going to specify 0.01, and then do wget ‑q ‑O‑, and then we’re going to go and supply the service name, so http://bevco‑inventory‑srv. And then we also need to supply the port, so :3000, and then we’re going to go and target api/inventory. We end it with a semicolon and done. So when we do this, this is going to go and start generating load. Let us go to the second terminal.

We can see that our load is now spiking. So, what I’m going to do is I’m just going to go ahead and pause and let this run as we go and generate load on our CPU. And ultimately, this is going to go and scale up our pods up to five. Okay, currently, you can see that we’re over 88%, which means that the autoscaling is going to begin. Okay, so we have a load of 87%, and our replicas are now up to 5.

Now, if I go over here and I just go and kill what is going on here, this will go and stop busybox, and then our pods are going to slowly start dying off, and we’ll go back to three. Okay, our load has dropped to 18%, which means that our replicas should be getting killed. All right, it did take a little bit of time. But as you can see, we are now back down to three replicas. If I come back over here and execute a kubectl get po.

And as you can see, we only have three inventory‑depl pods running. Okay, that’s great. So we have the ability to go and scale up the number of pods we have based off of the CPU percentage. But what if we want to do both memory and CPU at the same time? We can do this, but it’s going to require a little bit more of a sophisticated HPA, which we’ll be covering in the next demo. I’m Travis Thomsen, and I’ll see you in the next one..

Code Examples

# hpa-v1.yml - Horizontal Pod Autoscaler (v1)
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: bevco-inventory-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: bevco-inventory-depl
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50
# Créer un HPA via kubectl
kubectl autoscale deployment bevco-inventory-depl \
  --cpu-percent=50 \
  --min=1 \
  --max=10

# Générer de la charge pour tester l'autoscaling
kubectl run -i --tty load-generator \
  --rm --image=busybox:1.28 \
  --restart=Never -- /bin/sh -c \
  "while sleep 0.01; do wget -q -O- http://bevco-api-gateway-svc/api/inventory; done"

# Observer le HPA
kubectl get hpa --watch

Demo: Horizontal Scaling Continued

Hello again, I’m Travis Thomsen. Now that we start working with horizontal autoscaling, it’s time to take things a little further. So this is what we currently have right now. And we only have one thing that we’re looking at, which is going to be the CPU utilization percentage. This is what’s going to determine our pod to go and scale up.

But what if we want to go and scale on, not just on CPU, but also memory? Additionally, we do have the ability to go and control the behavior of our scale up and scale down, so let’s go and take a look at that first. So one of the first changes we’re going to make is that we need to go and change the apiVersion. Currently, we’re using autoscaling/v1. We need to go and change it to v2. For the most part, everything is going to be the same all the way down to maxReplicas.

After that is where we go and add in our new changes. So, we have behavior. And behavior is going to be a part of spec. And then we have scaleUp, and then the policies. Now type can be something like pod, or it can be a percentage, and this is going to be the percentage of pods that are going to go and scale up during a certain period.

So we have a period in seconds, which is currently 60, which means that when we hit an autoscaling event, it’s going to scale up one pod every 60 seconds. Likewise, we can also set a scaleDown policy. And just like before with type, we can either have a pod or percentage, and then we supply the value that we’re going to go and scale down by. So right now, once we are out of our autoscaling event, every 60 seconds, our HPA is going to reduce the number of pods by one. The nice thing about it is that we’re able to go and tailor your scaleUp and scaleDown based off of the needs of your application.

The other thing we’re going to be adding is going to be metrics. Metrics is going to go and take a list of types and that is going to be of type resource. Below that, we have Resource. And then we supply the name of the Resource, in this instance, it’s CPU. And then we have our target.

Our type is going to be set to Utilization. And then we have an averageUtilization, so in this instance, we have 80%. Once we’ve gone and surpassed the 80% utilization, this is going to cause an autoscaling event for our pod. We also have another Resource type. But this time, it’s going to be for memory.

And we’re going to go and set our Utilization to an average Utilization of 70%, which means that if we go over 70% utilization for our memory, that will likewise go and trigger an autoscaling event. Okay, wo let’s go and jump into our demo here. We’re going to go and continue working with our HPA. So we’re going to go and modify it, and we’re going to go and add behaviors and metrics to it. And then we’re going to go and reapply our manifests.

And once everything has been deployed out, we’re going to go and hit it with busybox again to go and flood it with a request to cause an autoscaling event. Okay, so let’s go and jump into it. I’m already logged into my EC2 instance. And if I do an ls, you see that we have our manifests directory, so let’s go and navigate to that. The file I want to go and edit is going to be inventory‑hpa.yml.

Now, the first thing we need to do is go and modify the apiVersion. So we have version one currently, we need to change it to version two, or these changes will not work. Now, if I come down to the very bottom go and delete this last line here. I’m going to create a new line. The first thing we’re going to go and add is going to be our behavior.

So we’ll start things off with behavior. Now, the first behavior we need to go and add is going to be scale up, so scaleUp. And now we go and supply our policies. Now, policies is going to take a list, so we can technically have multiple policies here, but we’re only going to be dealing with one, and that’s going to be type and Pods. And Pods does need to be capitalized.

I’m going to go and supply a value. This is going to be the number of pods we’re going to scale up by, and then the periodSeconds, and that’s going to be 60. Okay, now we can go and supply our scaleDown policy. And again, Down is going to be capitalized. Next, we go and supply our policies, and this is going to be have type Pods as well.

And then we also have a period seconds, which is also going to be 60. Okay, now our behaviors are complete, it’s time to go and define our metrics. Now, metrics is going to go and contain a list, and that is going to be of type, and then Resource. Below that, we’re going to go and define our resource. I’m going to go and supply a name, which is going to be cpu.

And below that we go and supply our target. Our target is going to be of type Utilization. And now we go and set our averageUtilization, and we’ll be setting this 80. We have another type, which is we have type Resource. Next, we have resource.

Okay, we need to go and name our resource, which is going to be memory. Next, we go and supply our target, and then the type, which is going to be Utilization. And then below that, we have our averageUtilization, and we’ll be setting that to 70%. I’m going to go and save. I’m going to go and scroll up real quick because I did notice that I did misspell Behavior.

Let’s go and fix that. And now go and save and quit. Now, it’s going to apply our manifests, so kubectl ‑apply ‑f, and then inventory‑hpa.yml. Okay, did set a value to zero? Let’s take a look. So scaleDown policies.

Oh, okay, I didn’t add a type there. That makes sense. Let’s go and do that real quick. So, value of one. Let’s go and try this again.

Okay, configure. Let’s go and take a look at our HPA, so kubectl get hpa. And now you can see that we have two targets, one that is set to 80%, which is going to be for our CPU, and then 70 for the memory. So currently, we have a minimum of three pods, a max of five, and currently there are three. Okay, I’m going to come over to my second terminal window here.

I’m going to go and watch the HPA just to see how utilization is going to shape out. Come back over here and we’re going to go and generate some loads. So, we’ll be executing a kubectl run, so this is going to go and start generating load on our micro service. And hopefully, based off what we’re doing here, should see an autoscaling event coming up. So, if I come back over to my second tab here, we should start getting some Utilization reports.

Okay, as you can see, we’re not quite hitting that load to go and generate an autoscaling event just yet. But what I can do is lower the percentage on my CPU to go and do that. So let’s go and do that right now. Go and break out of this real quick. In this termimal, I have not gone over to the manifests directory, so let’s go and do that real quick, and edit our inventory‑hpa file.

So, I want to come down to Utilization for the CPU, and I going to change this to, let’s just do 60. And then save and quit, and kubectl apply ‑f, and then inventory‑hpa.yml. Okay, so now we’re going to go and watch our pod again. We’ll see where things are at. So currently, we have our targets now set to 60% on CPU.

And we are obviously over that threshold, which means that we should start seeing an autoscaling event now. Okay, so we do have an autoscale event going on. As you can see, we’ve so far only scaled up to four replicas. We have not quite hit five yet. But we are still over that Utilization, which is 73% currently, so we might actually see it get to five pods.

As you can see, our microservice has been running for quite some time. We haven’t quite hit that fifth replica yet, but it’s been holding pretty steady around in the fifties for utilization of CPU. So things, for the most part, are holding up pretty well. And what we can do now is just go and kill the load that is being generated on our microservice and just let things scale down. But even when I had it set to 80%, it didn’t even go and scale up, which is actually kind of nice based off of the load that was generating on it.

So, this just goes to show you that you have the ability to go and configure what your autoscaling is going to look like. You can set to how many pods you want to scale up and then scale down, and you have the ability to go and tune it based off of your memory and CPU utilization. So, I want to go and break out of the loop. Go ahead and, actually no, I’m going to go ahead and rerun it. What I want to do is come over here and break out the loop to stop generating load.

So we should start seeing CPU load backing off now, and then we can go and scale down to only three replicas. Okay, so enough time has passed and the microservice has scaled back down to only three pods. So we’ve gone and achieved what we wanted. That’s all I have for this demo. I’m Travis Thomsen, and I’ll see you in the next one..

Code Examples

# hpa-v2.yml - HPA avec comportement avancé et métriques multiples
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: bevco-inventory-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: bevco-inventory-depl
  minReplicas: 1
  maxReplicas: 10
  behavior:
    scaleUp:
      policies:
        - type: Pods
          value: 1
          periodSeconds: 60
    scaleDown:
      policies:
        - type: Pods
          value: 1
          periodSeconds: 60
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 50
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 70

S0804 Readiness and Liveness Probes

Hello again, I’m Travis Thomsen. And in this demo, we’re going to start working with Readiness and Liveliness Probes. Liveliness Probes are a mechanism that Kubernetes can use to ensure that your pod is healthy. And if it’s not, kubelet will go and restart that specific pod. Now, a pod can fail for any number of reasons.

There could be a seg fault or maybe it just crashed, or maybe it’s getting overloaded and is not responding. And by going and checking the Liveliness Probe, it is able to go and ensure that if a pod does die, that a new one will be created in its place. And the way it does this is by going and probing an HTTP endpoint. Kubernetes also has Readiness Probes. And Readiness Probes are a way to ensure that a pod is online before it starts routing traffic to it.

And just like with Liveliness Probes, there’s also an HTTP endpoint that it goes to check to if everything is up and running. And once everything is online, it is now added to the pool of pods that is available to be accessed by the service. Now, a pod is considered to be ready when all the containers within that pod report back that they are now live and pass the Readiness Probe. But for us, we’re only dealing with one container per pod, so this is not going to be an issue. In order to go and add a Readiness and Liveliness probe, we need to go and modify our deployment.

And as you can see, under containers, we have the readinessProbe. It’s going to go and check a URL, which is we’re doing an HttpGet on it, and we need to go and supply the path to that endpoint. So right now, we have api/inventory/health. And all this does is it just returns and OK. We also need to supply the port to go and access the container, which is port 3000, and we do the exact same thing for our livelinessProbe.

We have an HttpGet. We have a path to the health check, and a port to go and access it. Okay, so let’s go and jump into our demo. So what are we going to do here? We’re going to go and add our Readiness and Liveliness Probe to our inventory deployment. And then we’re going to go and hit it with busybox again, just to see how long it takes for these instances to come online.

So, let’s go and jump into it. I’m already logged into my EC2 instance. And if I do an ls, and go and navigate over to manifests. We want to go and modify the inventory‑depl file. What we’re going to do is go and add our Readiness and Liveness Probes right after our image here.

So, I’m going to go add a new line. So I’m going to go and add the readinessProbe. Again, the P in Probe does need to be capitalized, and then HttpGet, and the G in get does need to be capitalized as well. Now, first thing we need to do is supply our path, and this is going to be the path to our health check, so it’s going to be api/inventory/health. And after that, we go and supply the port, which is 3000, and that completes the Readiness Probe.

Let’s go and take care of the Liveliness Probe. Again, Probe does need to be capitalized. And now we do our HttpGet, and we supply the path to the Liveliness Probe. And again, we’re using the exact same URL. So it’s going to be api/inventory/health.

Okay, and now we need to go and include the port, which is going to be 3000. Now let’s go and save and quit. Now we just need to go and reapply the manifests file. So type kubectl apply ‑f and then inventorydepl.yml. All right, now if I go and clear my screen, I can do a kubectl get po.

And you can see that we, right now, have zero‑of‑one running right here for this particular pod, and this is what we’re talking about with the readiness check. So this pod is not yet ready. We have two endings. If I do another get in, you see that we still have one running now, we have two terminating, and we have two that are getting ready to come online. So, this will not flip to a one until that Readiness Probe has been passed.

And what we can do is we can do a kubectl describe po, and I’m going to go and grab this pod right here. And you can see that currently it is failing the Liveliness Probe. And again, this is fine. It’s going to fail up to the point where it’s ready. Let’s go and check on our pods again.

And as you can see, all three of our pods are now running. Now, what I want to do is I’m going to go and modify the hpa file. I’m going to have it where I only have one pod by default and then we go and scale up to five. So now we’re going to go and apply the changes, so kubectl apply ‑f and then inventory‑hpa.yml. So let’s go and see this in action.

What I’m going to do is a keubectl get po, and then I’m going to use the ‑‑watched flag to go and watch my pods. What I want to do is I’m going to go and kill off one of the inventory pods, and we can actually watch it in real time. Get recreated, go and wait until it’s ready, and then finally terminate the other pod. So, let’s go and take care of that. I want to go and grab this one right here.

So I’m going to go and execute a kubectl delete po, and then I go and paste in the pod. Oh, I misspelled delete. Come over here and we’re going to go watch this in real time. So as you can see, we have one‑of‑one terminating, and then we have it pending, and then creating container. And as you can see, zero‑of‑one running.

Now, it will become one‑of‑one running once it goes and passes the Readiness Probe. Okay, so as you can see, we now have one‑of‑one running, and it goes and terminates that other pod. So I’m going to go ahead and break out of this and clear my screen, and we’re just going to go and reset. Now I want to go and start flooding our microservices with request. And therefore, we can go and watch it spin up in real time, Okay, as you can see, our load generator is running.

Okay, we now have a pod in the process of being spun up, and we have zero‑one running currently. Okay, that pod is now online. Now the second container is in the process of being created. Now that second container is ready and it has been added to the pool. Okay, so I want to go ahead and call this demo good.

We have demonstrated that when we have an autoscaling event, our Readiness Probes will not go and add that pod to the load balancer until everything has finally passed. I’m Travis Thomsen, and I will see you in the next one..

Code Examples

# Readiness et Liveness Probes dans un deployment
spec:
  containers:
    - name: bevco-inventory
      image: <ecr-uri>/bevco-inventory:latest
      ports:
        - containerPort: 3000
      readinessProbe:
        httpGet:
          path: /api/inventory/health
          port: 3000
        initialDelaySeconds: 5
        periodSeconds: 10
      livenessProbe:
        httpGet:
          path: /api/inventory/health
          port: 3000
        initialDelaySeconds: 15
        periodSeconds: 20

9. Summary

Summary

Okay, it is official. We have reached the end of this course, and it’s time to do a quick recap. So, in the first module, we talked about some of the issues that we encounter as developers when it comes to pushing code to production. Some of these issues include things like manual deployments, dependencies, as well as a lack of a rollback strategy. We then talked about some of the ways we can go and resolve these issues using containerization.

And again, containerization is not a silver bullet, but it does help us with the issues that I just listed. We talked about what it means for an application to be Cloud Native by going and following the twelve factors in the twelve‑factor app. And by doing this, it allows us to go and deploy our application to any cloud environment. And then after that, we looked at the architecture of the application that we’ll be using throughout the course. We then moved on to cover the basics of Docker and Kubernetes.

We started off by talking about the fundamentals of containerization, which includes what exactly are Docker images, how we go and build them out using a Dockerfile, and how we can go and use a Docker image to create a container. We also talked about pods, which are the smallest computing unit within Kubernetes, and how we can go and deploy them out using a manifests file. We then went and followed that up by talking about the additional workload resources that we can work with such as ReplicaSets and Deployments. Because, by default, pods are not accessible to the network, we talked about how we can use services to go and make our pods publicly accessible. We then moved on to go and start working with Kubernetes and AWS by going and creating an EKS Cluster using eksctl.

And then we went and created some container registries for each of the microservices in our application. After we got our EKS environment set up, we moved on to go and containerizing our microservice. And the way we did that was by going and creating Dockerfiles for each of the microservices and then using Docker to go and build out each of the images, and then finally pushing each of the images up to the container registry. After we went and containerized our microservices, we moved on to going and deploying everything out to EKS. Now, some of the things that we did during this module was go and create a RabbitMQ cluster using a Kubernetes operator.

We also took a look at how we can go and use persistent storage in the form of a Storage Class. We used this primarily with our RabbitMQ cluster, along with our MongoDB database. You also learned how to go and use Secrets to manage sensitive information, specifically the RabbitMQ login information. And remember, in Kubernetes, Secrets are based64‑encoded, which means they are not encrypted. And then we also went and created some deployment manifests to go and deploy out all of our microservices to EKS.

And in the final module, we start talking about how we can go and scale up our microservices. We started off by talking about request and limits, limits were specifically used to go and determine whether a microservice need to go and scale up. We deployed out the Metric Server, which is one of the components that we need in order to use autoscaling. And finally, we finished things off by talking about readiness and liveness checks. Readiness checks are a way of making sure that our pods are not marked online until they are fully up and running.

And liveliness checks were then used to go and make sure that if there’s any issues with our pod, and it fails to check in, that it gets replaced. I just want to say thank you so much for taking my course. And if you’re looking to go and take another one, and if you’ve not taken any of the previous courses within this path, I highly recommend you go and check out those courses as well. I’m Travis Thomsen, and I’ll see you in the next one..


Search Terms

node.js · microservices · deploying · scaling · apis · backend · full-stack · web · microservice · kubernetes · containerizing · eks · cloud · images · inventory · native · production · service

Interested in this course?

Contact us to book it or get a custom training plan for your team.