Dockerfile Creating a custom docker image: DevOps with Docker and Node.js + Mongodb/Redis Part #2

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so now that we got our express application complete or the demo express application uh let's work on setting up our docker container now for this video i'm gonna assume that you already have docker installed on your local machine if you don't go ahead and do that now just follow the instructions on their website it's fairly straightforward just make sure you follow the directions for your respective operating system but once you have docker installed on your machine head on over to hub.docker.com and i want you to just search for node within that search bar right there once that's finished loading you'll see that the first result is the official node docker image so this is a public image provided by the node team and it's a fairly lightweight image that basically has node already installed for us so that we don't have to do this ourselves and if you take a look at the documentation you'll see that we've got all of the various different versions that it supports so you can get version 15 version 14 all the way back down to version 10 if you really want and it's got directions for this image or any specific things that are relevant to this image when you want to deploy a container from it now this docker image right here is not going to have everything that we ultimately need for our application because the whole idea behind docker and an image is that the image is going to have every single thing that's needed for your application to work and so for our application we obviously need to get our source code into the image and we also need to get all of our dependencies like express any other dependencies that our application may need so to do that what we're going to do is we're going to create our own custom image and we're going to base this custom image off of this node image so we're going to take this node image we're going to copy all of our source code into that node image and then we're going to install all of our dependencies like express and then that final image is going to have everything that we need to ultimately run our application so let's get started on doing that now okay so let's get started on creating our own custom image to create a custom image we need to create a docker file so the docker file is just going to be a set of instructions that docker's going to run to create our very own customized image so let's create a new file and we're going to call this dockerfile with a capital d now in our docker file it's going to have a set of commands that docker is going to run to create our own personalized image and the first command that we always have to do is we have to specify a base image so when you create a custom image what you're ultimately doing is you take a base image or a known image of some sort doesn't matter where the image from it can come from your own docker repository it can come from docker hub it can come from anywhere you just need a image that docker has access to and we're going to tweak it a little bit so that it contains all of our source code it contains all of our dependencies and things like that so in this case you know we already found our um our base image it's going to be this node image because that's really the only thing that we need to run right we just need it to have node and anything else to run node so we're going to take this as our base image and the instructions here is going to show you how we can ultimately use that so here you just specify node and then you can do colon and then the specific version you want if you don't specify the version i forget what version it grabs but if you read the instructions it's probably gonna say it grabs like version 14 or something like that or maybe the latest version right so what we do is we do from and we'll capitalize from and then we say node because that's the name of that uh image or our base image and then we can do colon and then the version we want so i'm going to specify version 15 not that we need version 15 we can run 14 or really any version we're not doing anything specific to any new versions i just want to show you guys how to actually specify a version uh so um that's something that's absolutely needed uh the next command is technically optional um but it's still recommended and that's called the workdir command and i'm gonna set that to slash app so what this command does is it sets our working directory of our container uh to be the slash app directory within the container so i know this slash app directory exists in the container because i've run the node image and i know it's got a slash app directory but setting the work directory is really helpful because anytime you run a command when you set the work directory it's going to run that command from this directory so we can put all of our application code in slash app and we can run node index.js on slash app and it's going to run it automatically in slash app without us having to specify uh so the working directory just uh is the directory where you run all your commands and it's also the directory where if you copy any files to your container it's going to by default send it to this directory so this is just recommended but it's not technically necessary now the next thing we want to do is we want to copy our package.json file which is this file which contains all of our dependencies and anything else that we need and we're going to copy it into our docker image so let's go to um so we can run the copy command and so we copy the path to the package.json file which is our current directory so we just do package dot json and then we have to specify the directory we want to copy it to in our image uh and so i'm gonna do this dot which means the current directory and the reason why i do that is because we set our working directory up here to be slash app so when you do dot it's going to assume the slash app directory we could technically also just do slash app same result but since we have the working directory set we can just specify it relevant relative to that directory uh the next thing is once we have our package.json remember it's got a list of all of our dependencies we want to actually install our dependency so we want to run an npm install so in our docker file to run a command we can do run and we can do npm install all right so we now have our package.json file copied over and then we run npm install now we've got express installed for us the next thing we want to do is and this part's going to be a little bit confusing but we're going to copy the rest of our files so all of our source code everything else into our docker image so we'll do a copy again and here instead of specifying a specific file i'm just going to say the current directory so it's going to grab every single file every single folder within our current directory and we're going to copy it to just like we did here where we just did a dot which is going to send it to the slash app we're going to do the same thing so we can just do dot or dot slash same thing and right here you might be a little confused you might be wondering well why do we copy the package.json first and then copy all of the files over do we even need this step before if we're going to copy all of our files this should copy our package.json and it does the reason why i split it up into two different steps is a little bit of an optimization technique so let me explain how docker images actually work when you create an image from a docker file it takes each one of these steps and it it treats it as a layer of the image so you could think of an image as just basically these five steps or five layers so once you build all five layers you have the ultimate image or the final image so this first command creates one layer of the image this second command creates another layer of the image this third command creates the third layer the fourth layer and the fifth layer and they all kind of build on top of each other and what's important is that after each layer the docker docker actually caches the result of each layer and what i mean by that is um when we run uh docker build when we actually build our image for the first time what's gonna happen is that it's gonna run this first step and it's gonna cache the result so it's gonna say hey look we downloaded the node image from docker hub and then we cache that result right we then set the working directory to slash app and we cache the result of that we then copy package.json we cop we cache the result we then npm install cache that result and then we copy all of our code and we cache that result and this is important because let's say we decide to rebuild the image again right if nothing changes docker is efficient it knows that nothing's changed in any of these layers and it just takes the final cache result of step five which is the last layer and it just gives that to you so if you run docker build which is the command to actually create the image the first time you run it it's going to take a long time because it's got to run all of these steps and especially the npm install if you have a lot of dependencies it's going to take quite a while but the second time you run it if nothing's changed you'll see it'll be done in less than a second and that's because it's cached all the results and the reason this is important and the reason why i split this up into two different steps is i want you to think about what happens during our development process right when we are actively working on our code what changes our package.json does not change very often right i mean we do occasionally add new dependencies that's normal but it's for the most part your source code changes but your package.json and your dependencies don't change very frequently and so by splitting this up into two different steps what happens is we cache each of these layers right and so we're going to cache uh the node image we're going to cache the working directory and in reality those two will never change right we're never really going to change those two so uh we're always going to essentially cache the result from step two and onwards but the thing about docker is if any layer changes right say that layer three changes and what i mean by layer three changes is that if package.json ultimately changes uh where maybe we add a new dependency we have to rerun step three and all of the steps after that because we don't know how that's going to impact step four we don't know how it's gonna impact step five and so by caching um by splitting these up into two different steps uh we can say that listen if package.json never changes then we're going to uh cache that result and since realistically when we're actually programming package.json is just not going to change so we're going to cache that result and since package.json is cached then we're going to also cache the result of npm install because nothing's really changing so we cache those results and so when we change any of our source code uh within our application the only step that really changes is layer 5 where we copy the rest of our code and so we only need to rerun step five however if we didn't have this split up into two different steps where we have a copy package.json and then copying the rest of our files what would happen is that anytime we changed our source code technically it would rerun everything including the npm install because it doesn't know that we only changed our source code it just sees that listen this step where we copy all of our files has changed we're going to have to rerun all the steps after that so by doing this we know that package.json will always be the same so we can cache the result of these two steps and only make and only run step five which is the changing of our source code so it's a little bit of optimization if it didn't make sense i don't think i did that great of a job of explaining it but i'll show you guys this when we actually build our containers how it actually caches the results of each step and how it's a little bit of an optimization to actually do this and split this up into two different steps all right so the next thing that we want to do is we know our application is going to be listening on port 3000 so let's do um expose so we're going to say our container is going to expose port 3000 and then finally when we start our container we want to tell it what command to run right and since this is a node application and our entry point into our node application is this index.js we have to tell it to run index.js so we do cmd brackets and then we're going to do node and then index dot js alright so when we deploy our container it's going to run in index.js so this is at runtime and this is at build time so hopefully you guys understand this so this is when we're building the image this is the command that's going to be assigned to the container when we actually run the container and so that's all we really need um we're going to go ahead and actually create our image now so let's go to our terminal down here and i'm going to stop our express server because remember we're no longer going to be developing on our local machine we'll be developing on the docker container so make sure you stop your local instance of your application all right and let's build our docker container oh sorry our docker image we're building the image right now not the container itself so we'll do a docker build and then we're going to specify uh the path to our docker file it's actually called the context it's not necessarily the path to the file um it has a little bit more of a meaning to it with but i don't want to spend too much time going i just think about it as the path to the docker file so this docker file is in the current directory so we're just going to do a dot so let's run that and i realized i forgot to save my file so let's save that and i'm going to rerun that and i want you to pay attention to the output notice what's happened and i think this is kind of important when you're trying to understand what's happening uh you can see that on step one of five it says we're going to grab uh the node image from docker dayo dot io so it's pulling the image from the uh from docker hub right and as i said each one of these is a separate step or a separate layer right if we go down we go to step two and it says working directory is set to slash app you can see that it says cached so you're not going to see it say cached on your machine that's because i ran this as practice before i recorded this video but it's not going to say that it's cached when you ultimately run this so so keep that in mind but if you run this again if you run it again right what should happen is that it should cache all of the results right and so now all the ways down to step five it's cached so if you run it again like i said there's an optimization where it actually caches the results and the second time you run it it's going to be much much faster so now what we're going to do is we're going to do a docker image ls and you can see the new image it created um this is the one without a name because we didn't specify a name you also see the node image that it pulled from docker hub which is node 15. now i don't like the fact that we didn't give this a name so let's do a docker image rm this is going to delete the image that we just created and i'm going to pass in that image id and if we do a docker image ls you can see that it's gone now so now we're going to go back to the docker build command that we ran but this time we're going to pass in a specific flag so we'll pass in the dash t flag so here we can give it a name i'm going to call this node app dash image all right so once that's complete we'll do a docker image ls and now you can see we've got our image that we just created so now that we have our image let's go ahead and run it and let's test it out see if everything works so we'll do a docker run and we'll do node dash app image so here we're just specifying the image that we want to create a container from which is this image that we just created but before you hit enter there's a couple of flags that we got to pass so first of all i want to give my docker container a name so that i have some kind of way to identify it so we can pass in the dash dash name option and we'll call this node app so keep in mind that last uh the last entry in my command is the name of the image that we're creating a container from this is the name of the container that we're creating and then finally there's one more flag i want to pass which is dash d so that means it's going to run detach mode because by default when you create a docker container from docker run you're going to be attached to the the cli or the console or whatever it's called but here i can run in detached mode so that my command line's still free and open uh so let's hit enter and it looks like it successfully created my container i can do a docker ps and we should see that there's a container open at the moment all right so let's test this out and what i'm going to do is let's just go to my local host colon 3000 hit refresh let's see what happens all right so it doesn't look good it's spinning which most likely means there's something broken and it looks like there is uh don't worry guys i know exactly what's wrong i perfectly did this uh so let's tackle exactly what's wrong with our docker container in the next section
Info
Channel: Sanjeev Thiyagarajan
Views: 431
Rating: 5 out of 5
Keywords: docker, node, nodejs, express, dockerfile, image, npm, install, dependencies, tutorial, programming
Id: buto7CVdHYU
Channel Id: undefined
Length: 16min 7sec (967 seconds)
Published: Tue May 18 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.