One way to solve this issue is using a smaller base image like node:lts-slim or the node:lts-alpine image. The slim images are also based on Debian Stretch but have fewer preinstalled programs. The alpine-based images on the other hand are the smallest. Alpine Linux is a lightweight, secure Linux distribution made for containers. For example, when developing a Node.js application, you need node installed on your machine. You don’t need alpine linux. You don’t need to package your nodemodules into an immutable build. You don’t need little containers to exec into to make significant changes. You just need to be able to execute node and npm. For more information on how App Service runs and builds Node.js apps in Linux, see Oryx documentation: How Node.js apps are detected and built. Configure Node.js server. The Node.js containers come with PM2, a production process manager. You can configure your app to start with PM2, or with NPM, or with a custom command.
Before you begin to run your Node.js application in a Docker container, or even build the app into a container, you have to answer an important question and make a key decision:
Which base Node.js image for Docker do I choose for my app?
The easy answer – and probably the most common one – is to specify the Node.js version you wish to use and take the full image for that version.
This is the mostly safe answer as it will give you a container in which you can do practically anything without having to install or configure any other tools; only your code.
It may not be the right choice, as you’ll see below. But in general it’s a safe choice as it includes a stable release of the Debian linux system (as most Node.js images do) with many pre-configured tools and dependencies.
Select Your Node.js Version, First
Before you select which version of Linux you want to build from, it’s important to pick your Node.js version.
There’s really only one thing you need to know when doing this. And that is:
Do Not Specify
FROM node As Your Base Image
If you specify “FROM node” without a version number tag, you will always be given the latest version of Node.js.
While this may sound like a great thing, at first, you will quickly run into headaches when you rebuild your image and find your application doesn’t run because a new release of Node.js no longer supports an API you’re calling or makes other changes.
You should always specify at least a major version number tag.
More realistically, you should specify a minor version as well.
You can optionally specify a patch number but this is not as necessary. There are typically very few breaking issues between patch releases.
Now that you have your Node.js version selected, it’s time to deal with the specific linux distribution and image options.
Selecting Your Linux Distribution
In addition to the major Node.js version numbers, there are other options from which you can choose for your image, including these tag name extensions:
- the default image (aka ‘jessie’)
- (and others in various combinations)
But before you make your decision on which image to use, you should know that the decision is not permanent.
In fact, it’s fairly simple to change the image from which you’re building. In truth it’s often far more challenging to change the Node.js version than to change the base image from which you build.
Don’t take the choice too seriously, then. Do consider a few of the following points on what each of the many images offers, though.
Wheezy, Jessie, what?
As mentioned before, most of the Node.js images are built from Debian linux. This is a very stable, very popular distribution of Linux.
This is also where many of these odd names come from.
Like many long-living projects, Debian uses code names for various major versions of it’s operating system. You can find a list of which version is what name on the Debian release page.
Not all of the Node.js images are built from Debian, however. There are a few other image, including distributions of Alpine linux and Scientific Linux to name a few.
However, you only need to care about 2 of these Linux distribution options, in my opinion: Debian and Alpine.
Selection: Full, Slim or Alpine?
Unless you’re looking for a very specific version of Linux and Node.js, for a very specific reason, I would stick with either the latest version of Debian (currently “jessie”), or Alpine Linux.
This drops your choice for the base image down to 3.
- The full image (with version number tag!)
- The ‘-slim’ image
- The ‘-alpine’ image
Full vs `-slim`
Both the full Node.js image and the ‘-slim’ image are built from Debian Linux (v8 “jessie” at the time of writing this). The major difference being the tools and libraries that are installed by default.
If you travel the hierarchy of Dockerfile builds and tags, you’ll find that the full version of the image builds from the same core ‘jessie:curl’ tag as the slim version.
The full version, however, adds a significant number of tools, including:
- source controls software, such as git, subversion, bazaar, and mercurial
- runtime libraries and build tools like make, gcc, g++, and others
- libraries and API sets such as imagemagick, a dozen other lib* libraries), and others
The end result of the tools and libraries that are installed into the full Node.js image is an image that starts at 650MB.
But, in spite of it’s size the full Node.js image can save a significant amount of drive space if you are using it for multiple images. This is one of the beautiful parts of how Docker manages images.
If you need these libraries and tools, then, this is a great option. If you’re building many images that need these tools, this is an especially important option.
If, however, you don’t need these tools and libraries – or you don’t have a lot of hard drive space and want to be more in control of the image contents – then the ‘-slim’ version of the image is probably what you want. This version runs around 250MB to start.
The third option from which you should choose is the ultimate in small images, however.
Alpine Linux: ‘-alpine’
Alpine Linux is a distribution that was almost purpose-built for Docker images and other small, container-like uses. It clocks in at a whopping 5MB of drive space for the base operating system.
By the time you add in the Node.js runtime requirements, this image does move up to around 50MB in space. But even at 10x the original Alpine size, it’s still 1/5 the size of the the `-slim` option.
My Recommendation: Alpine Linux
For my work, and for the work that I’m putting into my WatchMeCode guide to building Node.js apps in Docker, I prefer Alpine linux.
Alpine provides a great balance of incredibly small size with options for adding the build tools and libraries that you need. Even with a full build tool set installed, it only hits around 200MB. That’s still less than the ‘-slim’ option, while providing native compilation for things like bcrypt and other libraries.
There are a few caveats to note with the Alpine distribution, however.
The largest of which is that you may not be able to run all of your needed libraries. Alpine uses ‘musl libc’ instead of ‘glibc’. While this may not mean much to you right now, it does mean that you can’t install and use the Oracle Node.js driver, among other things.
For the most part, however, Alpine linux is a great distribution to use as a first choice.
Alpine Linux Nodejs Install
And remember, you’re not stuck with the decision you make now. It’s not that difficult to change from Alpine to -slim or the full version, later.
Alpine Linux Nodejs 14