Complete Intro to Containers (feat. Docker) Add Dependencies to a Node.js App
Transcript from the "Add Dependencies to a Node.js App" Lesson
>> Let's together do a more Complicated Node.js Application so, we just did like the Hello World or the my God, lol of Node.js, right? Which is to say is not a very realistic application it's one file that's executed and, kind of where we get into more complicated measures with Node applications is we have to start worrying about Dependencies, right?
[00:00:24] This is actually kind of like half the reason we have Docker in the mix at all is that we can freeze and control our dependencies, right? So as most people know, node has this thing called npm, npm does not stand for node package manager, but it is the node package manager.
[00:00:40] So we're going to do is I have this file here inside of the more complicated no JS app, what we're gonna do is we're gonna go over to our project again, and I'm gonna open my sidebar here, and I'm gonna say New Folder. And this one's gonna be called more-complicated-nodejs-app, okay?
[00:01:01] Inside of here, I'm gonna create a new file, this again, will be called index.js, and I'm going to be copying everything that's in here. Which you can see here I more or less took from the hapi-pino example, hapi.js is one of the most popular Node.js server-side frameworks, it's like Express, I quite like it, my good friend Eran Hammer writes it.
[00:01:25] And this does relatively the same thing, it has some logging functionality, which is what or it will rather momentarily or does rather hapi-pino. So you can see here it downloads from hapi/happy and downloads hapi-pino which is a logging tool for happiness js. So as you can see, this has now two dependencies, so what we're gonna do is we're gonna come into our command line here, I'm gonna close my sidebar here.
[00:02:01] All right, so, where am I? I am in nodejs so I'm gonna go up a directly and into more complicated node app, and I'm gonna say npm, init-y, so first of all if you don't have nodejs installed like on your host computer you probably will have to go do that, it's pretty easy to install.
[00:02:22] I do, so I'm gonna say npm init- y, I would suggest being on neither node 10 or node 12. I'm on node 10 right now, but this would work easily just as well as 12. Okay, and node npm- y just generates a package.json for you, and the- y means don't ask me any questions just do it.
[00:02:45] So now if you look in here it say, I have package.json right there, right? And I'm going to say npm install, and I'm gonna say @happy/ happy, and happy-pino like that. People frequently ask me like don't you need --save that's not required anymore, NodeJS just just automatically does it.
[00:03:12] See actually there's a flag to not save which is how it should have been in the first place, there we go. We installed 73 packages, And you can see now that I have a node modules directory, I have a package.JSON package.JSON, you could totally do this with yarn as well, I have no opinion on the matter they both do the job adequately.
[00:03:34] I just use npm because it's great and it's already installed and I don't have to do anything for it. All right, so now I have an entire project if you wanna just see what if it works if the node index-js, you can see there that it's now running.
[00:03:51] If I click here on this link kind of opens here, and you can see here that it's returning a bit of json that's just a success:true. And then I'll put a bunch of information about what the response was and the request, all that kind of stuff. So I'm gonna shut that down and we're gonna come back over here, so now we're gonna create a Docker file inside of our more complicated node app and say new file, Docker file.
[00:04:27] We're gonna start from as you may imagine node:12-stretch, and you can do stretch or stretch-slim, but at this point we all have stretch installed, so my Docker extension here. Cuz I have a Docker extension installed for Visual Studio Code which I suggest all of you install, we maintain it at Microsoft so I think it's okay.
[00:04:50] It'll do these kind of auto completions for you as well. And, I mean, I'm not actually gonna go over it too much in this course, but just so you know, it is worth exploring here, all this stuff that we're doing from the command line, you could totally run directly from VS code.
[00:05:08] All right, so from node 12 stretch there, I'm gonna say user node just like we did before, work there and we're gonna do /home/node/code. And what we're going to do is we're gonna say copy, -- chown node colon node like we did before. But I'm gonna say copy everything in this directory over into home/node/code, right?
[00:05:33] So it just moves everything over into the container, so that's what the dot does means everything from here goes into everything over there. Okay at this point I want to say CMD["node", index.js"] right? So this looks relatively the same, the only thing that we really changed from the last section is this.
[00:06:01] So I'm gonna close that I'm just gonna continue calling it my note app, again, you can call these different things if you want them to, I don't particularly care, so I'm gonna just overwrite it again. And everything should just work, and I should be able to, Run my app.
[00:06:22] So this is working, and that's fine, but that's because I did the npm install on my host computer, it's a couple problems but there's one, if you're running this in CI then the node modules won't already be there, right? Because we don't commit our node modules, that's the first problem, the second problem is node has the concept of native modules, right?
[00:06:59] So what we have to do is we have to run npm install inside of the container, right? That has to happen inside of the container. So let's go ahead and stop this, and just to prove my point, if I say remove node_modules right now, if I had a nickel for every time I typed this, I'd be a very rich man.
[00:07:19] All right, so now if I build it again, and I do run, it is gonna be like, I don't not understand this, right? Because it's not gonna find any of those modules, right? So we can't depend on the node modules actually being there, so what we're gonna do, is we're gonna come in here and we're gonna to say RUN, this runs any sort of arbitrary shell command that you want it to run, run npm.
[00:07:45] And as most of you would probably think to run npm install, right? I'm gonna suggest one that I think is better than npm install for this, npmci so npm ci is actually going to adhere to whatever is in the package-lock.json, right? So this is actually locked down to very specific versions, which is what you want in your like automation environments, right?
[00:08:10] You want it to be like exactly as close to everything as possible that you had, and it's faster. It ignores a bunch of stuff that npm Install does for you and npm ci doesn't need to do so, it actually runs fast as well. So inside of Docker files I'm going to invite you to not use npm Install, use npm ci instead, Kind of a best practice there.
[00:08:36] All right, so now if I come back in here and build again, This step will take a bit longer, right, cuz it's gonna go through and all the NPM installs, what happened? Yes, this would be a problem, so now we're running into permission errors. So the issue now is that it doesn't own code, you're gonna run into permission errors all the time when you're working with Docker, like just buckle up and be prepared for for such a premise.
[00:09:20] So if I run Ls- lsh, I could see in here, That this particular directory is owned by root, so when I'm trying to do npm install, it's trying to make changes to this root directory, that's a problem, right? So how do we handle this? Well, the way that you're gonna handle is you're gonna go instead of doing this worker right here, this is always gonna do it as node or as route.
[00:09:49] I don't think you can tell it necessarily even where to do it yeah, I don't think you can. So, what we're gonna do instead of instead of saying, letting that creative we're just gonna say right here, run make their home/node/code. Now because this is user node right here, it is going to run this as the node user.
[00:10:13] Now, if I do it again, Now it's gonna be able to do everything that it needs to because it is the correct user, and now if we go run this again, Everything should be working it and because I ran with publish right here 3000 3000, we should be able to go in here and open link.
[00:10:39] Very cool, right? All right, something I do wanna call out here because it's an issue I ran into when I was making this and inevitably one of you is going to run this as well. Notice here instead of happy I bind to host 0000, if I bind this to localhost, which 99 times out of 100 ends up being semantically the same like that, this will not work.
[00:11:07] This will not allow this to escape the container when you run it on localhost, it's a hard loop back that it cannot escape itself, right? So, that's why we have to bind to 0000 that will allow you to get outside of the container