Deploy a Nest.js App With Docker + Kubernetes on Google Cloud

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey there today i'm going to show you how to deploy an sgs application using docker and kubernetes so we're going to dockerize an sjs application and then use it to deploy it into a kubernetes cluster and we're going to use google cloud engine to be able to actually deploy this into a production environment so let's go ahead and get started i'm going to use the nest cli to generate a new project and i'm going to call it sjsk8s which stands for kubernetes here so let's go ahead and actually scaffold this with npm and wait for the project to initialize so once we've finished installing the dependencies we can cd into our app folder and then run npm run start dev to start the app up and then you can go ahead and open up the app in a code editor of your choice and so we just have a basic nestgs server running here with our app controller with our simple uh get route here and just to make sure everything is running up okay open up postman and we should be able to make a request to local host port 3000 and see the return hello world from our get route so the first step in uh deploying this application to a kubernetes cluster is building it into a docker image so to do or do that we're going to go ahead and create a docker file here and this docker file is essentially a formula or a set of instructions for how to build our application in any environment so to get started we're going to use the from keyword here to base our image off of node alpine which is a lightweight linux distribution that will include node out of the box which is what we're going to need to run the app and then we're going to make sure we label this stage of the build as development this is going to be a multi-stage build and we'll see why in a second here so now that we are extending this node alpine image we're going to specify the working directory for our app in this case it's going to be user source app so now that we have a working directory all subsequent commands will be relative to this directory so now what i want to do is i want to copy using the copy keyword and i want to copy all of our package.json files so in this case it'll be the package and the package lock i want to copy that into the root directory which is currently our working directory and now that we've moved the pack json over i want to run npm install to install all of our dependencies now once we have all of our dependencies available we're going to go ahead and copy the entire application so all of our files that we currently have we're going to move them into our working directory and then lastly we're going to run npm run build to actually build the nest js application so now we've actually built the nest js app we're going to go ahead and declare the next stage of our build process here so we're still going to extend the node alpine image but we're going to label this stage as production and these labels can be anything you'd like it's just to separate out the different build stages so next we're going to set an arg here and this is going to be the node environment so this will this argus just scoped to this docker file so to actually pass it to our build process we're going to pass the m keyword and then specify the nodem is equal to well the arg that we just defined nodem which will of course be production and now we're going to go ahead and actually just copy the working directory command from up here we want the same working directory for this new build stage so every time we declare a new build stage all the previous commands uh are no longer relevant so we need to redeclare the working directory additionally we're going to copy over our package.json just as we've done up here and now we're going to run npm install again as we did before but now we're only going to install the core dependencies in our package.json we don't want to install any of the dev dependencies and we used these dev dependencies to build the application in the first place but we don't need them necessarily when we run the app so we can specify that we only want these core dependencies that required by the app when it runs and the reason we do this is to keep our image as light as possible so after we've installed the dependencies required to run the app we can copy over all the files as we've done before and lastly this most crucial stage is we are going to copy from development the first stage of our process here we're going to copy over user source app dist so remember up here when we run ran the build command this outputted the nestgs application to our working directory user source app and then dist so we want to copy that dist folder over to our current working directory in the production build stage so now we have the nestgs application built and only the dependencies required to run it we can finally specify the command to execute and run the app which in this case will be node and then we can specify disk slash main which is the file that is executed to start the nest js application so these are all the steps required to package our sjs application into a docker file and now we can actually use it in a kubernetes environment so let's go ahead and see how we do that so to set up our kubernetes cluster first off make sure that you actually have a cluster available so if you're using docker desktop it actually comes with the ability to start up a kubernetes cluster you just need to go into your settings for docker desktop kubernetes and make sure you've enabled kubernetes which will start a single node cluster so once your kubernetes server is running we should be able to run cubectl get namespaces and see uh your default namespace which means we're ready to actually work with kubernetes so let's go back into our code editor and i'm going to create a new folder here called k-8s which will host all of our kubernetes related manifests so the first thing we're going to need to create is a deployment which describes to kubernetes uh the application we want to create now we're just going to supply some default fields here the api version will be apps v1 the kind will be a deployment so a deployment will ensure that we always have the specified number of replicas of pods running which are essentially instances of our application so we're now going to specify some metadata here and just provide the name of this manifests we'll call it nestjsk8s and now we will add the actual spec here so we need to provide a selector for the deployment to tell it to match uh the pods that we're gonna end up creating so we're going to have a match label here and we're going to match the label app we're going to call this nest jskh and now we can actually specify the replicas so this is the number of instances we want of our application running so in this case we'll just do two and then we provide the actual template for the pod that will be running so now we'll provide this set of metadata on here and we'll give it a label so now this is the label that our deployment will match so we want to have the same label here so that our deployment is correctly matching this pod which actually will run our an sjs container so now we've specified the metadata we'll have the spec of the actual pod and we'll specify the containers that we'll be running here so we're only gonna have one container we can give it any name i'll stick with our nest jsk8s pattern and now we're gonna specify the name of the image that we're going to run now i'm gonna call this m way next jsk8s and we're going to see how we can actually deploy this image in a second here let's go ahead and finish by adding a port so we know our nest js application is running on port 3000 so we need to expose that port uh in the pod that's running so we can specify a container port and give it a port of 3000 so now we have the manifest to actually create our pods or instances of our application we need a way to actually build the docker image we specified and use it here in this manifest so in order to push our image to a central repository you can create a free docker hub account so go hub.docker.com go ahead and create an account and then once you've done that we can hit the create repository button and then this is where we specify the account name so my username was emway and then you can give the repository a name whatever name you'd like i just called it sjsk8s and then go ahead and create this repository so after you've gone ahead and created that repository you want to make sure you've actually logged in on the command line so you can use docker login and enter your credentials that you used when you created your docker hub account so now that we have a docker hub account and a place to actually push our image up to we need to actually go ahead and build it so we can use docker build give it a tag name okay and this is going to be the name of the repository that we just created so in my case it's mg you would replace this with your repository name and then the name that you gave the repository so i use an sjsk8s and then the path to where the dockerfile lives so in this case it's a relative path uh and then we're gonna go ahead and just build this docker image so you can notice here docker is actually going through each of the steps we specified in our docker file and it's building our application so that it can run it inside of a container now it's important to know that docker actually is going to cache each one of these individual steps so it'll be quicker next time we run this because it does implement caching on each one of these steps now after we finished building the docker image we're going to run docker push and then specify the name that we just specified in the tag so i'm going to push this to the repo that i've created mgue and sjsk8 and then go ahead and wait until all your layers are finished pushing to the repository so now that our docker image is pushed up to the docker hub repository this image here that we specified in our deployment will correctly pull from the repository we specify by default kubernetes will use the docker hub repository so it knows to match this with the repository that we created now let's go ahead and actually deploy our application locally we're going to cd into the k8s folder we created and then we can use cubectl create and then specify the file files in this case deployment.yaml so actually after we create the deployment we can run cubectl getpods and we can see our two replicas here are running locally so we can use qctlogs and then paste the name of the pod and we can see our nest.js application logs are outputted here so now we've created our pods we need a way to communicate with them and to do that we're going to create a service and what a service does is it will uh give us a ip address that we can use and then it will load balance each request to a given pod that is running the container that we want so in the case folder we'll create a service.yml file we're going to specify another api version here v1 i'll give it a kind of service we'll specify the metadata here and as we've done before we'll give it a name i'll call this an sjsk it's as we have been doing and now we have the spec here so i'm going to give this a selector so this is going to tell the service which deployment we want to target when a request comes in so in our case we gave our deployment a name of app nest jsk8s so let's go ahead and specify that selector here so that a request is routed properly now that we've done this we need to specify the ports that our service will listen on the protocol here will be tcp and we of course know that the port that we want to target is port 3000 which is where our nest js application is listening for requests lastly we're going to specify the type here and this is going to be a node port a node port will open up this service for requests on each node in our cluster in this case we only have a onenote cluster this local machine i'm running kubernetes on but in a real cluster this will allow us to use any node ip address to communicate to our application so let's go ahead and open up the terminal again and we'll do cube ctl create and then we'll pass the service.yaml we then should be able to run qctl getservice and see our nest gsk8 service here type node port so if we've set everything up correctly we should be able to open a postman and execute a request on localhost and we're going to use the port specified here this will be different for you this port here is the node port we want to talk to so if we execute this get request we can see our hello world response from our next js application which is great so now that we've successfully deployed this application locally using a kubernetes cluster we want to actually deploy this on the cloud so we can use this api in the real world and in production so in order to accomplish this we're going to use google kubernetes engine which is a kubernetes provider a really good one easy to use and new customers actually get up to 300 dollars in free credits so you can totally try this out completely free and see how it works if you're not logged in you should see a try free button here otherwise you can go straight to your console so after you've created or signed into a google cloud account head inside the console and you can click up here to select a project or create a new one if you don't have one already so i've created one called nesgus k8s and that's the one i'll be using here now after that we can search for the kubernetes engine project and this is what we want here so if this is your first time with kubernetes engine you'll just want to click the blue button that says enable this api and wait for it to become enabled after that we can see this page here where we select to create a cluster and we want to use the autopilot cluster option which will automatically scale and configure our cluster for us so go ahead and click gke autopilot and configure that cluster now we can have some options where we have specify the name and the region and make sure this is a public cluster so after that we can click create and google cloud will automatically begin provisioning our cluster for us now this is going to take a little bit of time for the cluster to finish becoming provisioned and in the meantime we want to make sure we have the google cloud sdk installed on our machine so that we can communicate with the cluster so i'll include a link to these docs in the description where it describes how to install google cloud sdk if you don't already have it essentially we need a supported version of python on our machine and then there are instructions here based on your operating system so in my case i had the mac os 64-bit we simply need to install the package and move it into your users directory your home directory uh open up and unzip this file and from there we just need to run these scripts specified so this install script and lastly we'll run the init script here so after you have done that you should be able to open up your terminal and run gcloud so while this is still provisioning we should be able to still connect to the cluster we can click on the name of the cluster here and then we want to click on the connect button up here and get this command for command line access so that we can use the qctl command in our cluster so simply we're just going to copy this command specified and paste it into our terminal here and this command will automatically update our cube config to use this newly created cluster but once our cluster is fully provisioned and we see the green check mark we can go back to our command line here and run cube ctl get namespaces and we should see our newly created namespace three minutes ago and we won't have any pods in our default namespace which makes sense and so now we're going to go ahead and deploy our kubernetes manifests however there's one small change that we want to make to be able to deploy uh our service here now we don't want to use a node port but we actually want to take advantage of google cloud's load balancer features so if we specify a load balancer as the type of the service here google cloud will automatically provision us an external url that we can use to make requests to our service which is exactly what we want to communicate to our app so with this small change we can now run cube ctl create file and then just provide our whole directory here and we should uh see our deployment and our service get created properly now if we wait a little bit of time for our pods to get provisioned we should be able to see our two nesgs pods running properly and if we run keeps the tl get service we should see our load balancer service now notice we have an external ip provisioned here and this is what we're going to use to actually make a request to our application so go ahead and copy this external ip address and we can actually use the target port here to talk to this service so if you open up postman and enter our external ip and give it the port of 3000 and send off this request we can see we get a hello world response back from our next js application which is great to see our app has been successfully deployed in a production kubernetes environment so that's all for this one and if you have any questions or problems setting this up please let me know in the comments leave a like and be sure to subscribe for the next one
Info
Channel: Michael Guay
Views: 30,188
Rating: undefined out of 5
Keywords:
Id: cNh1CouQCWc
Channel Id: undefined
Length: 18min 23sec (1103 seconds)
Published: Sun Jan 09 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.