Create a Custom Image with a Dockerfile running Node.js

Joel Lord
InstructorJoel Lord
Share this video with your friends

Social Share Links

Send Tweet

You will learn how to create your own images that will include all the source code of your application, along with a specific version of Node.js and all the dependencies that are needed. Once you are done, you will be able to share this image with other people and this will ensure that everyone is running the same environment. It will event let people that don’t have Node.js run this server. This will also have the added benefit of cleaning up everything once you close the application.

You'll notice that we will run into the same error stating we can't connect to the database. This is expected and we'll fix this in Allow Container to Communicate through Docker Networks

Instructor: [0:00] In the last session, you started a MySQL server by using a container that you pre-configured with everything needed to run this server. You used an image that was pre-built by the MySQL team. What happens if you want to share your own image to be shared with your team? This is what we will see in this lesson.

[0:19] You will learn how to create your own images that will include all the source code of your application, along with a specific version of Node.js and all the dependencies that are needed. Once you are done, you'll be able to share this image with other people. This will ensure that everyone is running in the same environment. It will even let people that don't have Node.js run the server.

[0:43] This will also have the added benefit of cleaning up everything once you close the application. If you tried to create a few memes in the last lesson, you'll notice that you might have a bunch of files in your temp folder. These are the files that are created during the process of extracting the frames and regenerating the caption GIF.

[1:02] When we will run this application inside a container, all of this will be cleaned up as soon as we stop this container. The first thing you'll want to do in order to prepare your application to run into a container is to identify any variable that could be stored in an environment variable. This would be any value that would vary based on where the code is running.

[1:24] Examples of this would be a baseURL for your API. It would most likely be different from your production environment, test environment, and development environment. The same could go for log files or, in the case of this application, the database configuration.

[1:43] Thankfully, the software developer that worked on this project isolated those variables in a file called "config.js," so you won't have to dig too far. For each of the values in this file, you can change it to use a matching environment variable.

[1:59] You can leave the default values there for now by using a OR operator with double pipes. This way, if your application can't find an environment variable, it will fall back to the default values. Your application will still run locally without adding those variables.

[2:15] Another variable that could change would be the GIPHY API key. This value will need to stay a secret, but you'll want your server to be able to download the code from your repo and run everything. By storing this value in an environment variable, you would be able to keep it a secret and store this value on the server instead of in your source code. This variable is found in the API keys file.

[2:42] Don't put in a default value here. This will let you go into your gitignore file and remove the API keys line. This file will now be added to your repository and will rely on an environment variable to get the value of that API key.

[2:58] Next, you will want to create an image that can then be shared with the rest of your team. To create your own image, you will use a Dockerfile. This file will describe how the image is to be created. It will list a series of layers to create your own custom image. First, you can go back to your backend directory. Then from here, create a file called dockerfile.

[3:20] You can now open up your code editor and start working on that Dockerfile. A Dockerfile file always start with a FROM statement. This tells Docker what base image to use and how to build on top of it. For your backend, you will start with a FROM Node 14. This base image contains both the node executable and npm.

[3:48] Next, you will specify a working directory for our application. This could be anything. In our example, we will use /app. You will also need to create two subfolders that are used by the application. The run command will let you specify a command to be executed inside the container.

[4:13] Note that those two folders will be created inside the /app folder since we specified this to be the working directory in the last step. Now you can copy both your package.json and package-lock.json files. Then you'll run the npm command to install all the dependencies needed by your application.

[4:36] Note that you're only copying the package.json file here and not the entire directory. This will allow you to create an image that takes full advantage of the Docker layer caching, and this will significantly speed up your build process. Now that the dependencies are installed, you can copy all the code and assets that are required for your application by using the copy statement.

[5:05] Finally, you will need to specify which command is executed to start the server. Up until here, all those commands are executed to create your Dockerfile. The next command will be the one that will be executed when you use that Docker run command. In our case, the main file for this server is /app/index.js. You will use the command node/app. You now have a set of instructions that Docker will use to create your image.

[5:37] In order to start this image build, you can use the command docker build. You will also need to name your image. To do so, you will use the -t flag to specify a tag. You can also add a version number after the name of your image, if you'd like. If you don't, it will automatically append that latest tag as the version number.

[5:59] Finally, you need to specify the path to the Dockerfile that you just created. In this case, this is located in the current working directory, or dot. You should now see each of the 10 steps being run and see a message telling you that the image was successfully built.

[6:17] You can now test this image with a docker run command. This will be very similar to the containers you saw in the previous lessons. First, you will use, docker run. Then you will need to map some ports. In our case, we'll map the port 3000 to the port 3000 inside our container. Then you can give it a name. We'll use --name back.

[6:42] Next, you'll want to run this in detach mode with the -d flag. You'll want to clean it up once it closes with the --rm flag. Finally, you can use the name of the image that you used in the previous step, Case QRL -back.

[6:59] Now, try hitting your API to make sure that it is running. You can do that by opening up a new browser tab, or by using a QRL command to localhost:3000/help. Either way, you should be getting an error. It seems like the server isn't started. Because the container is running in the background, you could never the detailed error message. The server actually crashed.

[7:26] You can stop Docker by using docker stop and then validated that nothing is working anymore by using the docker ps command. This will list any running containers that you have on your system. You might have the Case QRL Db container still running, but you shouldn't have the Case QRL back container.

[7:46] To see what happened, you can execute the docker run command without a -d flag. The container will now output everything that the Node.js application would output in the same standard output. To see it, we can open up a new tab, do our QRL localhost:3000, and go back to the original tab. You can see here the full error trace.

[8:10] You can see that the error starts and outputs an error of type ECONNREFUSED. Does that remind you of anything? We're back to the start, it seems. The Node.js back end application can't find the database anymore.

[8:24] This is because the container is looking for a database on localhost, but localhost in the context of the container only has the backend service in it. Let's stop this container from running. You'll now need a way to tell your application how to connect to a database by using a network. This is what we'll see in the next lesson.