:::: MENU ::::

Node.JS, Gulp and OpenShift 3 – Custom assemble script FTW

I’m heading to India for workshops with some of Red Hat‘s big SI partners, and one of them requested some use case information around Node.JS and Gulp on OpenShift 3. Since I have never worked with any of these technologies, I had to do some research.

Gulp is kinda-sorta a build… uh… system… for Node.JS. It supports a number of plugins and other things that can be used during the build phase to produce your Node application. Seems simple enough. However, OpenShift’s source-to-image process for Node doesn’t know about Gulp out of the box. So, a little bit of customization is required. And by “a little bit” I mean two lines. First, a refresher.

OpenShift 3 introduces the concept of source-to-image. Source-to-image is the process that OpenShift uses to combine an existing Docker image that has a runtime already installed with your code. Red Hat calls this runtime image a “builder”. I’m using one of the Node.JS images from Red Hat’s registry:

rhscl/nodejs-4-rhel7

The build process involves a script called assemble. Here’s the Node.JS assemble script that comes with the Node.JS builder image:

#!/bin/bash
 
# Prevent running assemble in builders different than official STI image.
# The official nodejs:4.4-onbuild already run npm install and use different
# application folder.
[ -d "/usr/src/app" ] && exit 0
 
set -e
 
# FIXME: Linking of global modules is disabled for now as it causes npm failures
#        under RHEL7
# Global modules good to have
# npmgl=$(grep "^\s*[^#\s]" ../etc/npm_global_module_list | sort -u)
# Available global modules; only match top-level npm packages
#global_modules=$(npm ls -g 2> /dev/null | perl -ne 'print "$1\n" if /^\S+\s(\S+)\@[\d\.-]+/' | sort -u)
# List all modules in common
#module_list=$(/usr/bin/comm -12 <(echo "${global_modules}") | tr '\n' ' ') # Link the modules #npm link $module_list echo "---> Installing application source"
cp -Rf /tmp/src/. ./
 
if [ ! -z $HTTP_PROXY ]; then
        echo "---> Setting npm http proxy to $HTTP_PROXY"
        npm config set proxy $HTTP_PROXY
fi
 
if [ ! -z $http_proxy ]; then
        echo "---> Setting npm http proxy to $http_proxy"
        npm config set proxy $http_proxy
fi
 
if [ ! -z $HTTPS_PROXY ]; then
        echo "---> Setting npm https proxy to $HTTPS_PROXY"
        npm config set https-proxy $HTTPS_PROXY
fi
 
if [ ! -z $https_proxy ]; then
        echo "---> Setting npm https proxy to $https_proxy"
        npm config set https-proxy $https_proxy
fi
 
echo "---> Building your Node application from source"
npm install -d
 
# Fix source directory permissions
fix-permissions ./

The above script is pretty simple. It basically just sets some config options and then runs:

npm install -d

In your source code repository, you can create a folder, .sti/bin, and insert your own assemble script in it. When the source-to-image process is executed, it will run your assemble script instead of the built-in one. As you can see, the assemble script is simply a Bash script in this case. It could be a script written in any locally executable language. Probably even in Node!

I am using a forked version of a Node+Gulp application written by Grant Shipley located here. Grant didn’t design the app to run on OpenShift, so I simply took it and added an assemble script. You can find my repository here: https://github.com/thoraxe/nodebooks

Since the assemble script is just a Bash script, we can actually run scripts from scripts. The built-in assemble script is located in the folder:

/usr/libexec/s2i/

Since Gulp itself is written in Node, we can launch our Gulp task with Node. Here’s the entirety of my customized assemble script:

# vim: set ft=sh:
#!/bin/bash
 
# original assemble
/usr/libexec/s2i/assemble
 
# gulp tasks
node node_modules/gulp/bin/gulp.js inject

That’s all there is to it! The script above calls the original assemble that’s built-in to the image. This causes the Node.JS dependencies to be installed. That ends up giving us Gulp. Then, we use Node.JS to execute the locally-installed Gulp, and to run the task inject. Since the Gulp tasks are very specific to my application, this actually makes sense. Not only does Gulp allow us to treat configuration as code, as we create additional Gulp tasks we can simply update which tasks are run by changing the assemble script.

Neat, huh? If you want to try OpenShift, head on over to www.OpenShift.com