Bundle a Node.js app within a rock¶
This tutorial describes the steps needed to bundle a typical Node.js application into a rock.
Prerequisites¶
- snap enabled system (https://snapcraft.io/docs/installing-snapd) 
- LXD installed (https://documentation.ubuntu.com/lxd/en/latest/installing/) 
- Docker installed (https://snapcraft.io/docker) 
- a text editor 
Install Rockcraft¶
Install Rockcraft on your host:
sudo snap install rockcraft --classic
Project Setup¶
Starting in an empty folder, create a src/ subdirectory. Inside it, add two
files:
The first one is the package.json listing of dependencies, with the
following contents:
{
    "name": "node_web_app",
    "version": "1.0.0",
    "description": "Node.js on a rock",
    "author": "First Last <[email protected]>",
    "main": "server.js",
    "scripts": {
      "start": "node server.js"
    },
    "dependencies": {
      "express": "^4.18.2"
    }
}
The second file is our sample app, a simple “hello world” server. Still inside
src/, add the following contents to server.js:
'use strict';
const express = require('express')
const app = express()
const port = 8080
const host = '0.0.0.0'
app.get('/', (req, res) => {
  res.send('Hello World from inside the rock!');
});
app.listen(port, host, () => {
  console.log(`Running on http://${host}:${port}`);
});
Next, we’ll setup the Rockcraft project. In the original empty folder, create
an empty file called rockcraft.yaml. Then add the following snippets, one
after the other:
Add the metadata that describes your rock, such as its name and licence:
name: my-node-app
base: [email protected]
version: '1.0'
summary: A rock that bundles a simple nodejs app
description: |
  This rock bundles a recent node runtime to serve a simple "hello-world" app.
license: GPL-3.0
platforms:
  amd64:
Add the container entrypoint, as a Pebble service:
services:
    app:
        override: replace
        command: node server.js
        startup: enabled
        on-success: shutdown
        on-failure: shutdown
        working-dir: /lib/node_modules/node_web_app
Finally, add a part that describes how to build the app created in the src/
directory using the npm plugin:
parts:
    app:
        plugin: npm
        npm-include-node: True
        npm-node-version: "21.1.0"
        source: src/
The whole file then looks like this:
name: my-node-app
base: [email protected]
version: '1.0'
summary: A rock that bundles a simple nodejs app
description: |
  This rock bundles a recent node runtime to serve a simple "hello-world" app.
license: GPL-3.0
platforms:
  amd64:
services:
    app:
        override: replace
        command: node server.js
        startup: enabled
        on-success: shutdown
        on-failure: shutdown
        working-dir: /lib/node_modules/node_web_app
parts:
    app:
        plugin: npm
        npm-include-node: True
        npm-node-version: "21.1.0"
        source: src/
Pack the rock with Rockcraft¶
To build the rock, run:
rockcraft pack
At the end of the process, a new rock file should be present in the current directory:
ls my-node-app_1.0_amd64.rock
Run the rock in Docker¶
First, import the recently created rock into Docker:
sudo /snap/rockcraft/current/bin/skopeo --insecure-policy copy oci-archive:my-node-app_1.0_amd64.rock docker-daemon:my-node-app:1.0
Since the rock bundles a web-app, we’ll first start serving that app on local port 8000:
docker run --name my-node-app -p 8000:8080 my-node-app:1.0
The output will look similar to this, indicating that Pebble started the app
service:
2023-10-30T12:37:33.654Z [pebble] Started daemon.
2023-10-30T12:37:33.659Z [pebble] POST /v1/services 3.878846ms 202
2023-10-30T12:37:33.659Z [pebble] Started default services with change 1.
2023-10-30T12:37:33.663Z [pebble] Service "app" starting: node server.js
2023-10-30T12:37:33.864Z [app] Running on http://0.0.0.0:8080
Next, open your web browser and navigate to http://localhost:8000. You
should see a blank page with a “Hello World from inside the rock!” message.
Success!
You can now stop the running container by either interrupting it with CTRL+C or by running the following in another terminal:
docker stop my-node-app
References¶
The sample app code comes from the “Hello world example” Express tutorial, available at https://expressjs.com/en/starter/hello-world.html.
