Skip to content

Instantly share code, notes, and snippets.

@stevenuray
Last active July 11, 2018 17:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevenuray/425a38ee864beaddf3702d3bb1b1039f to your computer and use it in GitHub Desktop.
Save stevenuray/425a38ee864beaddf3702d3bb1b1039f to your computer and use it in GitHub Desktop.
Dockerlith Application Container Entrypoint Script for Synchronizing Access to Shared NPM Dependencies
#!/usr/bin/env bash
# Application containers should not continue starting
# if their dependencies are unverified,
# so if any command in this script fails the container
# will stop it’s initialization process and
# an error message will be presented to the user.
set -euo pipefail
# Set variables here
# The resource to have synchronized write access is the node_modules directory.
# An empty, hidden file .npm_lock is created to use it’s file descriptor.
# The file descriptor to be locked is number 200.
# Finally, the .package_md5 file is used to store a hash string of the package.json file
# so no call to npm install is made unless the package.json file has changed.
readonly NPM_DIR=/app/src/node_modules
readonly LOCK_FILE=$NPM_DIR/.npm_lock
readonly LOCK_FD=200
readonly MD5_FILE=$NPM_DIR/.package_md5
# Define functions here
# Here is a generic function that locks a file with a file descriptor,
# using the flock unix command.
# Docker containers share the host’s kernel,
# so they can communicate with each other through these file descriptor locks.
lock() {
# Create lock file.
eval "exec $2>$1"
# Get exclusive, waiting lock on the file descriptor of the lock file.
flock --exclusive $2
}
# Releases the lock acquired with lock()
unlock() {
echo "This container is releasing the lock on the npm libraries"
flock --unlock $1
}
# Containers should only install npm libraries if the dependencies have changed
# in package.json. Therefore, package.json has an MD5 hash saved to a shared file
# each time the dependencies are installed.
# If package.json changes due to new dependencies,
# a different MD5 hash will be generated that differs from
# the one that has been saved.
check_npm_libraries() {
if [ ! -f $MD5_FILE ] || ! md5sum -c --status <<<"$(cat $MD5_FILE)"; then
echo "INVALID"
else
echo "VALID"
fi
}
# If the dependencies have changed, they are updated with a call to “npm install”.
# After this, the hash of the package.json file the dependencies came from
# is saved to the hash file.
install_npm_libraries() {
npm install grunt
echo "Installing npm Libraries..."
npm install --unsafe-perm --loglevel info
write_md5_sum_to_md5_file
}
write_md5_sum_to_md5_file() {
echo "package.json md5" $(md5sum ./package.json)
md5sum ./package.json > $MD5_FILE
}
prepare_npm_volume() {
#Try to get node_modules lock.
lock $LOCK_FILE $LOCK_FD
#Check status of npm libraries now that this container has the lock.
echo "This container has the lock on the npm libraries."
npm_library_status=$(check_npm_libraries)
if [ "$npm_library_status" == "INVALID" ]; then
install_npm_libraries
else
echo "Valid cached npm libraries detected, skipping npm install"
fi
# The lock must be explicitly released here,
# because the process is expected to continue after this script is done.
unlock $LOCK_FD
}
#Execute commands here
prepare_npm_volume
echo "arguments received: $@"
exec "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment