Serverless NodeJS / Native node_modules - node.js

I'm having an issue getting a node module to load in AWS Lambda using the Serverless Framework. One of my node packages uses native libraries so I used an EC2 to create the node_module folders and then copied them to my Serverless project. Everything works if I manually zip the project and upload to AWS Lambda but if I use serverless deploy without an artifact specified, I get an error about the module (specifically: ELF file's phentsize not the expected size regarding a .node file)
I've tried adding excludeDevDependencies: false which makes the deployment larger but still gives me the error. Currently, it only works if I zip the contents of the project folder and specify that file as the artifact to upload. Is there a different way to get a node module with native bindings to deploy with Serverless?
UPDATE: After turning off the exclusion of dev dependencies, packaging using serverless package and examining the expanded zip file serverless creates, I discovered the file sizes of the .o and .a files are different in the packaged version as compared to the original. Is this normal?

I ran into this problem and did some digging. It turns out that v1.21.0 of serverless broke packaging of binaries.
https://forum.serverless.com/t/serverless-1-21-0-breaks-sharp-library/2606
https://github.com/serverless/serverless/issues/4182
The recommended fix is to upgrade to v1.21.1.

Since Lambda runs on a Linux container, you should be running serverless deploy from a Linux machine.
This way, your native modules will be compiled for your target architecture which is Linux.
To check the deployment package that serverless creates, you can use sls package or sls deploy --noDeploy (for older versions), and inspect the .serverless directory that it creates. You'll see a zip file in here, extract its contents, and test the code from there.
If the contents of this zip is not what you expect (not the same as when you manually copy them), then maybe something is wrong with your file structure and/or serverless.yml.

Related

Serverless deployment to AWS Lambda missing modules?

First time dealing with serverless here. Have successfully deployed using serverless deploy after following the guide to migrating an existing express app over to serverless. But aws lambda keeps throwing an error:
“errorType”: “Runtime.ImportModuleError”,
“errorMessage”: “Error: Cannot find module ‘serverless-http’\nRequire stack:\n- /var/task/app.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js”,
So I’m confused. What am I doing wrong? The guide to converting an existing express app didn’t say we’d need to create an AWS Lambda Layer, but since it seems like Lambda can’t find the serverless-http module, does it mean that creating a layer is the fix?
Edit: my .zip file seems to only be an express.js file. I'm not sure if that's unusual but reading online reveals that most people seem to have a node_modules folder zipped up as well? I presume the lack of a node_module folder in the .zip file is causing this runtime.ImportModuleError fail? How do I get serverless to add a node_modules folder if that's the case?
node_modules folder is generally packaged with your code -- provided it exists in your directory (does it?).
If node_modules isn't installed on your local machine, then you can create it by using the npm install command. This command will install all the dependencies listed in the package-lock.json file (or package.json) -- sorry I'm not a node guy :(.
But it definitely sounds like you're not uploading your node_modules folder because it's not on your local machine. You have to initialize the directory first.

Deploy angular2 application

I developed an application in angular2 and now I need to deploy it.
Currently I have a wwww root folder containing:
html files
js files (generated from typescript)
css files (generated from scss)
/node_modules/ folders
/bower_componenets/ folder
The last two folders (node_modules & bower_components) are very heavy (300 mb and thousands of files) and it is very frustrating copy them using FTP.
Is there a way to keep only the needed files?
Thanks a lot
You can use gulp for creating bundle from the libraries into single file ex. vendor.js. Also deploying via ftp is very primitive. You should put your app on GitHub or Bitbucket and then log in to the server and pull your repository there and because you don't put the libraries folders into your git repository you will install the libraries on the server. If you want to go more advance you can use tool like Jenkins combined with gulp task for building your application. Jenkins will build your application automatically and deploy to your server on every push on your git repository
The following question could help you if you want to use Gulp:
How do I actually deploy an Angular 2 + Typescript + systemjs app?
Note that some answers are for beta versions and packaging changed for RC versions.
Angular-cli could also help you to build your application within the following command:
ng build -prod
Moreover using tree shaking could be interesting to minimize the weight of JavaScript files. See this article for more details:
http://blog.mgechev.com/2016/06/26/tree-shaking-angular2-production-build-rollup-javascript/

Compiled node.js module not getting correct library path when copied to different machines

My problem is a little complicated but I'll try:
I have a node.js application that needs to be completely prebuilt and bundled alongside standalone node.js (specifically 4.4.5 LTS), zipped and deployed to offline CentOS 6/7 machines, meaning I cannot do npm install, and no gcc/g++/python so I cannot do things like node-gyp rebuild.
Everything is working correctly except this module: ibm_db.
It's compiled with node-gyp after downloading the db2 cli drivers, but basically it's supposed to work like the regular DB2 client except all its dynamic libraries, binaries etc. are inside the module path itself (node_modules/ibm_db/installer/clidriver).
If I deploy the bundle (which includes all node modules in the tarball, including ibm_db) to another machine, it's probably going to sit on a different path from the machine on which I built the bundle. When I try to run the app like this: ./node app.js (here node is a symlink to the standalone node binary inside the unpacked bundle) i get this error:
Error: libdb2.so.1: cannot open shared object file: No such file or directory
Now, I can clearly see that libdb2.so.1 is inside node_modules/ibm_db/installer/clidriver/lib but the paths in bindings.gyp all use the original paths on the build machine which don't match, so I assume this is where the problem lies.
I can easily just add that path with ldconfig and it would work, however the user profile installing the app will not have superuser access so it's not a real option.
I tried setting the environment variable LD_LIBRARY_PATH but node.js deletes this entry from process.env on startup, and even if I programmatically set it like process.env.LD_LIBRARY_PATH='...'; it doesn't seem to do anything.
Is there any way to modify the library path for a compiled module without recompiling/rebuilding it? If it's possible I would assume that would be the easiest solution, but I couldn't find a way to do it.

Bundle Node.js dependancies in AWS Zip

Im creating a lambda function using Node.js, and Im looking to bundle the dependencies into my zip to be used in my Lambda function in AWS. Specifically Im using the ffmpeg library, and I've got it running locally using npm. Is there a way that I can bundle this dependency with the .zip file that I upload so that I don't have to configure the dependency in AWS?
Not only is there a way to bundle this into your deployment package, but you have to do it this way. Lambda functions can't download dependencies.
Here's the documenation: http://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html
Also you might want to look at this project: https://github.com/binoculars/aws-lambda-ffmpeg and possibly this thread: https://forums.aws.amazon.com/thread.jspa?messageID=680948 for more specific information about running ffmpeg on Lambda.

How to package & deploy Node.js + express web application?

I am new to Node.js programming and I have recently created a sample working web application using (express, backbone & other complimentary view technologies, with mongoDB). Now i am at a point where I want to deploy the same on a staging environment and I am not sure how to package this application and distribute the same. [I can take care of mongoDb and setting it up seperately]
I am from Java world and in there we create jars for reusable libs and war/ear packages for web applications which is deployed in a servlet container. Now in this case since node.js itself acts as a web container as well, how do i package my webapp?
Is there any standard format/guidelines of packaging node webapps built using express? (Is there a similar jar/war packaging systems for node apps?)
How do I deploy it once packaged? Would it become an exe, since it is also its own container?
PS: As of now I am thinking of just manually copying all the required source files into the staging environment and run npm commands to download all dependencies on that machine and then use 'forever' or some other mechanism to run my server.js. (Also, add some sort of monitoring, just in case app crashes and forever fails) I am not sure if that is the right way? I am sure there must be some standardized way of addressing this problem.
Deploying Node.js applications is very easy stuff. In maven, there is pom.xml. Related concept in Node.js is package.json. You can state your dependencies on package.json. You can also do environmental setup on package.json. For example, in dev environment you can say that
I want to run unit tests.
but in production;
I want to skip unit tests.
You have local repositories for maven under .m2 folder. In Node.js, there is node_modules folder under your Node.js project. You can see module folders with its name.
Let's come to the grunt part of this answer. Grunt is a task manager for your frontend assets, html, javascript, css. For example, before deployment you can minify html, css, javascript even images. You can also put grunt task run functions in package.json.
If you want to look at a sample application, you can find an example blog application here. Check folder structure and package.json for reference.
For deployment, I suggest you heroku deployment for startup applciations. You can find howto here. This is simple git based deployment.
On project running part, simply set your environment NODE_ENV=development and node app.js. Here app.js is in your project.
Here is relative concept for java and nodejs;
maven clean install => npm install
.m2 folder => node_modules(Under project folder)
mvn test => npm test(test section on package.json)
junit, powermock, ... => mocha, node-unit, ...
Spring MVC => Express.JS
pom.xml => package.json
import package => require('module_name')
There is no standardized way, but you're on the right track. If your package.json is up to date and well kept, you can just copy/zip/clone your app directory to the production system, excluding the node_modules.
On your production system, run
npm install to install your dependencies, npm test if you have tests and finally NODE_ENV=production node server.js
Some recent slides I considered to be quite helpful that also include the topic of wrappers like forever, can be found here.
Hope this might be helpful for somebody looking for the solution,Packaging of Node js apps can be done using "npm pack" command.It creates a zip file of your application which can be run in production/staging environment.
Is there any standard format/guidelines of packaging node webapps
built using express? (Is there a similar jar/war packaging systems for
node apps?)
Yes, the CommonJS Packages specification:
This specification describes the CommonJS package format for
distributing CommonJS programs and libraries. A CommonJS package is a
cohesive wrapping of a collection of modules, code and other assets
into a single form. It provides the basis for convenient delivery,
installation and management of CommonJS components.
For your next question:
2. How do I deploy it once packaged? Would it become an exe, since it is also its own container?
I second Hüseyin's suggestion to deploy on Heroku for production. For development and staging I use Node-Appliance with VirtualBox and Amazon EC2, respectively:
This program takes a Debian machine built by build-debian-cloud or
Debian-VirtualBox-Appliance and turns it into a Node.js "appliance",
capable of running a Node application deployed via git.
Your webapp will not become an exe.
few ways to approach this:
Push your code into Git repository, excluding everything that isn't your code (node_modules/**), then pull it in your staging environment, run npm install to restore all dependencies
create an NPM package out of it , install it via npm in your staging environment (this should also take care of all of the dependencies)
manual copy/ssh files to your staging environment (this can be automated with Grunt), than restore your dependencies via npm
I used zeit's pkg module. It can create cross platform deliverables for linux/win/macos. Actually used it in production and works fine without any issues.
It takes in all the js scripts and packages it into a single file.
The reason I used it is because it helps in securing your source code. That way in production at customers environment they will have access to application but not the source code.
Also one of the advantages is that at production environment, you do not actually need to have the customer install node.js as the node binaries also get packaged inside the build.
https://www.npmjs.com/package/pkg

Resources