Developer's Guide to the Node.js Reference Architecture

A Developer's Guide to the Node.js Reference Architecture

Michael Dawson, Lucas Holmquist
English

Overview

About

The JavaScript ecosystem is fast-moving and vibrant—but with so many options, it can be difficult to choose among Node.js packages. That’s where the Node.js reference architecture comes in.

A Developer's Guide to the Node.js Reference Architecture provides practical recommendations to help you be successful in your Node.js deployments. Drawing on real-world experience from Node.js teams at Red Hat and IBM,  this e-book provides recommendations about what components to use when building Node.js applications.

Explore guidance for functional components, development, and operations, with chapters devoted to the following:

  • Logging
  • Code consistency
  • GraphQL
  • Building good containers
  • Choosing web frameworks
  • Code coverage
  • TypeScript
  • Securing Node.js applications
  • Accessibility
  • Typical development workflows
  • npm development
  • Problem determination
  • Testing
  • Transaction handling
  • Load balancing, threading, and scaling
  • CI/CD best practices

Excerpt

What makes a good production container?

Before we dive into the recommendations for building good containers, what do we mean by a "good" container in the first place? What this means to the Red Hat and IBM team members is that the container:

  • Applies best practices for security.
  • Is a reasonable size.
  • Avoids common pitfalls with running a process in a container.
  • Can take advantage of the resources provided to it.
  • Includes what’s needed to debug production issues when they occur.

While the relative priority between these can differ across teams, these were generally important based on our experience.

What base images to start with?

In most cases, teams build their containers based on a pre-existing image that includes at least the operating system (OS) and commonly also includes the runtime—in our case, Node.js. 

In order to build good containers, it is important to start on solid footing by choosing a base container that is well maintained, is scanned and updated when vulnerabilities are reported, keeps up with new versions of the runtime, and (if required by your organization) has commercial support. 

The reference architecture includes two sections that talk about containers: container images and commercially-supported containers. Most of the teams within Red Hat and IBM are already using or moving toward using the Node.js Red Hat Universal Base Images (UBI) for Node.js deployments.

Apply security best practices

The first thing we talked about with respect to building good containers is making sure we applied security best practices. The two recommendations that came from these discussions were:

  • Build containers so that your application runs as non-root.
  • Avoid reserved (privileged) ports (1–1023) inside the container.

The reason for building containers so that your application runs as non-root is well-documented, and we found it was a common practice across the team members. For a good article that dives into the details, see Processes In Containers Should Not Run As Root.

Why should you avoid using reserved (privileged) ports (1-1023)? Docker or Kubernetes will just map the port to something different anyway, right? The problem is that applications not running as root normally cannot bind to ports 1-1023, and while it might be possible to allow this when the container is started, you generally want to avoid it. In addition, the Node.js runtime has some limitations that mean if you add the privileges needed to run on those ports when starting the container, you can no longer do things like set additional certificates in the environment. Since the ports will be mapped anyway, there is no good reason to use a reserved (privileged) port. Avoiding them can save you trouble in the future.