Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build for AWS Lambda #680

Closed
schaq8 opened this issue Nov 26, 2015 · 40 comments
Closed

Build for AWS Lambda #680

schaq8 opened this issue Nov 26, 2015 · 40 comments

Comments

@schaq8
Copy link

schaq8 commented Nov 26, 2015

I'm a Linux & node noob. I'm trying to run FabricJS (which requires node-canvas) in AWS Lambda. I've been able to follow the instructions to get up and running on an AWS Linux EC2, however, Lambda has me at my wits end. Anyone have any tips or pointers on how to get this compiled for AW Lambda?

@zbjornson
Copy link
Collaborator

This is actually a use case for me as well. I hope to try this this weekend and will let you know what I find. I think you'll have to bundle the SOs and change bindings.gyp to point to them.

@schaq8
Copy link
Author

schaq8 commented Nov 26, 2015

Zach, I'd be so grateful!

On Thu, Nov 26, 2015 at 12:20 AM, Zach Bjornson notifications@github.com
wrote:

This is actually a use case for me as well. I hope to try this this
weekend and will let you know what I find. I think you'll have to bundle
the SOs and change bindings.gyp to point to them.


Reply to this email directly or view it on GitHub
#680 (comment)
.

@zbjornson
Copy link
Collaborator

Didn't find time this weekend, and not sure when I'll get to this. If you want to try this on your own, you might check out the commits relating to the third bullet point here: #571

@zomgbre
Copy link

zomgbre commented Dec 3, 2015

+1 I'm also interested in this.

@zbjornson
Copy link
Collaborator

Also related: #641 (although they're not statically linking). You might find some good stuff in the forks from the people commenting there and in 571.

@ssomai
Copy link

ssomai commented Dec 4, 2015

+1 I'm also interested in this.

@mankins
Copy link

mankins commented Jan 17, 2016

I was able to compile node-canvas and get it running on lambda by building dynamic and using rpath. Since lambda always runs in the same /var/task this makes it:

 export LDFLAGS=-Wl,-rpath=/var/task/

and then build normally.

You should also make sure you're compiling on the same AMI environment that lambda currently uses: http://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html

@jalieven
Copy link

jalieven commented Feb 4, 2016

@mankins could you provide some more info on how you dynamically build node-canvas?

@mankins
Copy link

mankins commented Feb 4, 2016

Hey @jalieven here's some notes I made:

  1. Make sure you're compiling this on the same AMI that lambda currently uses:
    http://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html
  2. Lambda runs at /var/task (that's the path when you unzip), so something.so at the root of the zip file will be at /var/task/something.so.

We then want to build our libraries using an "rpath":

 export LDFLAGS=-Wl,-rpath=/var/task/
  1. Compile libraries according to: https://github.com/Automattic/node-canvas/wiki/Installation---Amazon-Linux-AMI-%28EC2%29

You may want to set the prefix= ~/canvas to have all the files in one place.

  1. Install node-canvas with npm
  2. cd node_modules/canvas; node-gyp rebuild
  3. mkdir /pkg and cp the .so files (/canvas/lib/*.so) there, using -L to dereference symlinks.
  4. scp the pkg directory to the local lambda folder, possibly putting the files in the right places. (.so in root, node_modules/canvas with other libs). You'll probably want to rearrange this.

Good luck!

@jalieven
Copy link

@mankins many thanks for your notes. Works like a charm!

@mauricio-trigueros
Copy link

@mankins Can you provide more details about the process?
I tried to follow your steps, but I think I miss something, because I am not able to make it work.
I got this error in AWS lambda:

{
"errorMessage": "libpng16.so.16: cannot open shared object file: No such file or directory",
"errorType": "Error",
"stackTrace": [
"Module.load (module.js:356:32)",
"Function.Module._load (module.js:312:12)",
"Module.require (module.js:364:17)",
"require (module.js:380:17)",
"Object. (/var/task/node_modules/canvas/lib/bindings.js:2:18)",
"Module._compile (module.js:456:26)",
"Object.Module._extensions..js (module.js:474:10)",
"Module.load (module.js:356:32)",
"Function.Module._load (module.js:312:12)",
"Module.require (module.js:364:17)"
]
}

My file structure (the zip that I upload to AWS Lambda) has the next structure:

  • Canvas.js
  • node_modules folder
  • pkg folder (with the *.so items, including libpng16.so.16)

In the AWS AMI instance that I am using to generate the zip file (same than you provide in your link), if I go to canvasexample/node_modules/canvas, and execute

ldd build/Release/canvas.node

The result that I get is:

linux-vdso.so.1 => (0x00007fff50dec000)
libpixman-1.so.0 => /usr/local/lib/libpixman-1.so.0 (0x00007fc31c71e000)
libcairo.so.2 => /usr/local/lib/libcairo.so.2 (0x00007fc31c418000)
libpng16.so.16 => /usr/local/lib/libpng16.so.16 (0x00007fc31c1e8000)
libjpeg.so.8 => /usr/local/lib/libjpeg.so.8 (0x00007fc31bfae000)
libgif.so.4 => /usr/lib64/libgif.so.4 (0x00007fc31bd9d000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007fc31ba98000)
libm.so.6 => /lib64/libm.so.6 (0x00007fc31b796000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fc31b57f000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fc31b363000)
libc.so.6 => /lib64/libc.so.6 (0x00007fc31afa1000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc31cbe0000)
libfontconfig.so.1 => /usr/lib64/libfontconfig.so.1 (0x00007fc31ad6b000)
libfreetype.so.6 => /usr/local/lib/libfreetype.so.6 (0x00007fc31aade000)
libxcb-shm.so.0 => /usr/lib64/libxcb-shm.so.0 (0x00007fc31a8dc000)
libxcb-render.so.0 => /usr/lib64/libxcb-render.so.0 (0x00007fc31a6d2000)
libxcb.so.1 => /usr/lib64/libxcb.so.1 (0x00007fc31a4b5000)
libXrender.so.1 => /usr/lib64/libXrender.so.1 (0x00007fc31a2ac000)
libX11.so.6 => /usr/lib64/libX11.so.6 (0x00007fc319f70000)
libXext.so.6 => /usr/lib64/libXext.so.6 (0x00007fc319d5e000)
libz.so.1 => /lib64/libz.so.1 (0x00007fc319b48000)
librt.so.1 => /lib64/librt.so.1 (0x00007fc31993f000)
libSM.so.6 => /usr/lib64/libSM.so.6 (0x00007fc319738000)
libICE.so.6 => /usr/lib64/libICE.so.6 (0x00007fc31951c000)
libexpat.so.1 => /lib64/libexpat.so.1 (0x00007fc3192f2000)
libXau.so.6 => /usr/lib64/libXau.so.6 (0x00007fc3190ef000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fc318eea000)
libuuid.so.1 => /lib64/libuuid.so.1 (0x00007fc318ce6000)

That I guess is not correct, because (If I understand), libpng16.so.16 and the other dependencies should point to my pkg folder (may be something like "/var/task/pkg/libpng16.so.16") , that is the same I will upload to Lambda, and same that would be executed, right? (I also tried to follow another similar issue in Package pre-compiled binaries with node-canvas for downstream consumers #641.

Any help is very very welcome!

Thank you very much!

@mankins
Copy link

mankins commented Feb 10, 2016

It sounds like you need to use the -rpath=/var/task/ of -rpath=/var/task/pkg ... you're basically baking in a search path for dynamic libs (.so) and so if you put them in pkg, you'll need to compile them that way.

@mauricio-trigueros
Copy link

Thanks! I arranged to make it work in the way you were describing.

I will continue playing with this "rpath" option!

Thanks again!

@willbamford
Copy link

I followed the process outlined by @mankins and created a GitHub repo with the compiled shared object (see src/*.so.*) files and an example with this working. Hope someone else finds this useful.

@navihtot
Copy link

navihtot commented Apr 4, 2016

Following @webseed notes I managed to get camanJS library working on AWS Lambda so here it it helps somebody.

@copypastedeveloper
Copy link

@mankins I'm sure i'm missing something very basic, but when I follow those instructions I don't seem to end up with any .so files in the lib directory, just .js ones. Any pointers would be great. here is the console output...

[ec2-user@ip-172-31-30-105 canvas]$ export LDFLAGS=-Wl,-rpath=/var/task/
[ec2-user@ip-172-31-30-105 canvas]$ cd node_modules/canvas/
[ec2-user@ip-172-31-30-105 canvas]$ node-gyp rebuild
gyp info it worked if it ends with ok
gyp info using node-gyp@3.3.1
gyp info using node@4.4.4 | linux | x64
gyp info spawn /usr/bin/python
gyp info spawn args [ '/usr/lib/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args   'binding.gyp',
gyp info spawn args   '-f',
gyp info spawn args   'make',
gyp info spawn args   '-I',
gyp info spawn args   '/canvas/node_modules/canvas/build/config.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/usr/lib/node_modules/node-gyp/addon.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/home/ec2-user/.node-gyp/4.4.4/include/node/common.gypi',
gyp info spawn args   '-Dlibrary=shared_library',
gyp info spawn args   '-Dvisibility=default',
gyp info spawn args   '-Dnode_root_dir=/home/ec2-user/.node-gyp/4.4.4',
gyp info spawn args   '-Dnode_gyp_dir=/usr/lib/node_modules/node-gyp',
gyp info spawn args   '-Dnode_lib_file=node.lib',
gyp info spawn args   '-Dmodule_root_dir=/canvas/node_modules/canvas',
gyp info spawn args   '--depth=.',
gyp info spawn args   '--no-parallel',
gyp info spawn args   '--generator-output',
gyp info spawn args   'build',
gyp info spawn args   '-Goutput_dir=.' ]
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
make: Entering directory `/canvas/node_modules/canvas/build'
  SOLINK_MODULE(target) Release/obj.target/canvas-postbuild.node
  COPY Release/canvas-postbuild.node
  CXX(target) Release/obj.target/canvas/src/Canvas.o
In file included from ../src/PNG.h:3:0,
                 from ../src/Canvas.cc:8:
/usr/include/libpng12/png.h:2657:31: warning: invalid suffix on literal; C++11 requires a space between literal and identifier [-Wliteral-suffix]
        fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
                               ^
/usr/include/libpng12/png.h:2665:31: warning: invalid suffix on literal; C++11 requires a space between literal and identifier [-Wliteral-suffix]
        fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
                               ^
/usr/include/libpng12/png.h:2673:31: warning: invalid suffix on literal; C++11 requires a space between literal and identifier [-Wliteral-suffix]
        fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
                               ^
  CXX(target) Release/obj.target/canvas/src/CanvasGradient.o
  CXX(target) Release/obj.target/canvas/src/CanvasPattern.o
  CXX(target) Release/obj.target/canvas/src/CanvasRenderingContext2d.o
  CXX(target) Release/obj.target/canvas/src/color.o
  CXX(target) Release/obj.target/canvas/src/Image.o
  CXX(target) Release/obj.target/canvas/src/ImageData.o
  CXX(target) Release/obj.target/canvas/src/init.o
  CXX(target) Release/obj.target/canvas/src/FontFace.o
  SOLINK_MODULE(target) Release/obj.target/canvas.node
  COPY Release/canvas.node
make: Leaving directory `/canvas/node_modules/canvas/build'
gyp info ok 
[ec2-user@ip-172-31-30-105 canvas]$ ls
binding.gyp  build  History.md  index.js  lib  node_modules  package.json  pkg  Readme.md  src  util
[ec2-user@ip-172-31-30-105 canvas]$ cd lib
[ec2-user@ip-172-31-30-105 lib]$ ls
bindings.js  canvas.js  context2d.js  image.js  jpegstream.js  pngstream.js

@mankins
Copy link

mankins commented May 15, 2016

@ncgonz doesn't look like you're compiling the libraries. (You missed the first step?) Have a look at @webseed's repo https://github.com/WebSeed/node-canvas-aws-lambda-example where it's been done for us.

@copypastedeveloper
Copy link

@mankins I looked into using that, he seems to have compiled against node version 0.10, which I cannot use. I have a dependency on jsdom, which requires node 4.3. I finally got everything compiled last night, and now have everything running on lambda. Hooray! Thanks for the pointers

@anandanand84
Copy link

Just created a gulp plugin to automate deployment of node-canvas in aws lambda which would handle both nodejs 0.10 and nodejs 4.3. jic if someone needs, https://www.npmjs.com/package/aws-lambda-node-canvas.

@abhi06991
Copy link

Hi...I am having the same problem. Am I missing something here?
Lambda runs on a system that will take care of the executing our package and running simultaneously many processes,etc. (I dont know what system is that).

@mankins : I just couldn comprehend this "Make sure you're compiling this on the same AMI that lambda currently uses".

Where can I get this info about the AMI that my Lambda function uses? Do I get a console for AMI where I can compile?

I have a few EC2 instances.Do I have to create an AMI for a particular EC2 instance? How to link my Lambda function with this AMI?

I know this may sound silly but I am really confused .

@navihtot
Copy link

navihtot commented Feb 16, 2017

@abhi06991 you need to create EC2 instance with ami that lambda currently uses (http://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html) then ssh there and compile your thing
[you cannot ssh to lambda]

@abhi06991
Copy link

abhi06991 commented Feb 20, 2017

Hey guys, I followed the instructions and everything is working fine except Font Rendering. No font is rendering and Paths to font folders are correct,I have verified it.

I have included the following .so files:

libcairo.so.2
libfreetype.so.6
libgif.so.7
libjpeg.so.8
libpixman-1.so.
libpng16.so.16

Do I have to include some other .so files?

@tomasdev
Copy link

@abhi06991 you probably want to do cp -L /canvas/lib/*.so.* /your/folder instead

@timsvoice
Copy link

@navihtot I found your how-to notes super helpful, thanks!

@navihtot
Copy link

navihtot commented Apr 6, 2017

@timsvoice np, glad that it helped somebody :)

@jgautheron
Copy link

Anyone managed to recently run everything successfully in Lambda? I'm using node-canvas through chartjs-node to render charts, I'm almost there but stuck on font rendering...

@tomasdev
Copy link

tomasdev commented Jan 9, 2018 via email

@jgautheron
Copy link

Basically the text is rendered as blocks, as if the font was not found.

@tomasdev
Copy link

tomasdev commented Jan 9, 2018 via email

@tomasdev
Copy link

tomasdev commented Feb 4, 2018

By the way, in case anyone needs it, here's the full list of commands I ran in a Linux AMI (the one that https://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html shows, currently 6.10)

Steps to build node-canvas for Lambda usage

  1. Create an AWS EC2 Instance (you can use the AWS Web Console) t2.micro based on the AMI from the link above
  2. SSH into it (you need the pem you created with it)
  3. Run the following commands, I suggest 1 by 1 to know if an error happened
export LDFLAGS=-Wl,-rpath=/var/task/
sudo yum groupinstall "Development Tools" -y
sudo yum install fontconfig-devel.x86_64 -y
sudo yum erase cairo -y

export PKG_CONFIG_PATH='/usr/local/lib/pkgconfig'
export LD_LIBRARY_PATH='/usr/local/lib':$LD_LIBRARY_PATH

sudo yum -y install zlib-devel

curl -L http://downloads.sourceforge.net/libpng/libpng-1.6.21.tar.xz -o libpng-1.6.21.tar.xz
tar -Jxf libpng-1.6.21.tar.xz && cd libpng-1.6.21
./configure --prefix=/home/ec2-user/canvas
make
sudo make install
cd ..

curl http://www.ijg.org/files/jpegsrc.v8d.tar.gz -o jpegsrc.tar.gz
tar -zxf jpegsrc.tar.gz && cd jpeg-8d/
./configure --disable-dependency-tracking --prefix=/home/ec2-user/canvas
make
sudo make install
cd ..

curl -L http://www.cairographics.org/releases/pixman-0.34.0.tar.gz -o pixman-0.34.0.tar.gz
tar -zxf pixman-0.34.0.tar.gz && cd pixman-0.34.0/
./configure --prefix=/home/ec2-user/canvas
make
sudo make install
cd ..

curl -L http://download.savannah.gnu.org/releases/freetype/freetype-2.6.tar.gz -o freetype-2.6.tar.gz
tar -zxf freetype-2.6.tar.gz && cd freetype-2.6/
./configure --prefix=/home/ec2-user/canvas
make
sudo make install
cd ..

curl https://www.freedesktop.org/software/fontconfig/release/fontconfig-2.12.0.tar.bz2 -o fontconfig.gz

sudo yum install libpng-devel -y

curl -L http://cairographics.org/releases/cairo-1.14.6.tar.xz -o cairo-1.14.6.tar.xz
tar -Jxf cairo-1.14.6.tar.xz && cd cairo-1.14.6
PKG_CONFIG_PATH=/home/ec2-user/canvas/lib/pkgconfig
PKG_CONFIG=/home/ec2-user/canvas/lib/pkgconfig
./configure --disable-dependency-tracking --without-x --prefix=/home/ec2-user/canvas
make
sudo make install
cd ..

sudo yum install giflib-devel -y

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.4/install.sh | bash

#After installing NVM you'll have to close your ssh session and reconnect.

nvm install 6.10

PKG_CONFIG_PATH=/home/ec2-user/canvas/lib/pkgconfig:/usr/local/lib/pkgconfig

# Gave up moment
sudo yum install cairo cairo-devel cairomm-devel libjpeg-turbo-devel pango pango-devel pangomm pangomm-devel giflib-devel -y

# Copy the pango dependencies
cp /usr/lib64/libpango*.so.* /home/ec2-user/canvas/lib/
cp /usr/lib64/libpango*.so /home/ec2-user/canvas/lib/

After that, you can npm install node-canvas into the ec2, and copy over SCP the folders in node_modules (should just be this library and the nan lib)
Copy that to your local node_modules before creating the zip (so whatever gets uploaded to Lambda, has these specially built modules)

@thenickdude
Copy link
Contributor

thenickdude commented Feb 10, 2018

I don't really understand why using "-rpath" and rebuilding the libraries from source should be required. According to the Lambda Documentation, LD_LIBRARY_PATH includes LAMBDA_TASK_ROOT (/var/task) and LAMBDA_TASK_ROOT/lib (/var/task/lib). So we should just be able to put libraries in there and have them found automatically.

I took the Lambda AMI and spun up a VM. I installed Node and development tools:

sudo yum groupinstall "Development Tools" -y
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.4/install.sh | bash

# Exit session and reopen here to make nvm available

nvm install 6.10

Then I installed node-canvas as you normally would:

sudo yum install cairo-devel libjpeg-turbo-devel giflib-devel pango-devel -y
npm install canvas@next

Then I copied the system libraries from /usr/lib64/ into a ./lib/ subdirectory in my Node project:

mkdir lib
cp /usr/lib64/{libpng12.so.0,libjpeg.so.62,libpixman-1.so.0,libfreetype.so.6,\
libcairo.so.2,libpango-1.0.so.0,libpangocairo-1.0.so.0,libpangoft2-1.0.so.0} lib/

I added an index.js to test Canvas with:

let
	{createCanvas} = require("canvas");

function hello(event, context, callback) {
	let
		canvas = createCanvas(200, 200),
		ctx = canvas.getContext('2d');

	// Write "Awesome!"
	ctx.font = '30px Impact';
	ctx.rotate(0.1);
	ctx.fillText('Awesome!', 50, 100);

	// Draw line under text
	let
		text = ctx.measureText('Awesome!');
	ctx.strokeStyle = 'rgba(0,0,0,0.5)';
	ctx.beginPath();
	ctx.lineTo(50, 102);
	ctx.lineTo(50 + text.width, 102);
	ctx.stroke();

	callback(null, '<img src="' + canvas.toDataURL() + '" />');
}

module.exports = {hello};

And a serverless.yml file to deploy it to Amazon for me:

service: canvas-test

provider:
  name: aws
  runtime: nodejs6.10
  stage: dev
  region: us-east-1
  memorySize: 128
  timeout: 10

functions:
  hello:
    handler: index.hello

The resulting project structure:

├── index.js
├── lib
│   ├── libcairo.so.2
│   ├── libfreetype.so.6
│   ├── libjpeg.so.62
│   ├── libpango-1.0.so.0
│   ├── libpangocairo-1.0.so.0
│   ├── libpangoft2-1.0.so.0
│   ├── libpixman-1.so.0
│   └── libpng12.so.0
├── node_modules
│   ├── canvas
│           ....
│   └── nan
│           ....
└── serverless.yml

I downloaded this entire folder to my local machine. Then I called serverless deploy to deploy it to Lambda, and serverless invoke --function hello and I got the successful result from it running on Lambda:

download

@tomasdev
Copy link

We could technically close this ticket and just leave that last comment as instructions for use in Lambda.

I went for the manual build because I didn't know where to take the .so and libs from. That is way easier, thanks @thenickdude

@thenickdude
Copy link
Contributor

I've added those instructions to the Wiki now:

https://github.com/Automattic/node-canvas/wiki/Installation---AWS-Lambda

@zbjornson
Copy link
Collaborator

Closing since @thenickdude added instructions (thank you!).

@natevw
Copy link

natevw commented Oct 25, 2018

Updated link is https://github.com/Automattic/node-canvas/wiki/Installation%3A-AWS-Lambda, which also includes the encouraging note:

Canvas 2.0 and 1.6 works out-of-the-box on AWS Lambda thanks to prebuilds. However, you must build your Lambda ZIP file on Linux (or a Linux Docker container) so that the correct prebuilt binary is included.

and cross-references #1231

@jwerre
Copy link

jwerre commented Jun 7, 2019

Is it still the case that this works "out-of-the-box" I'm getting the following Lambda error:

{
    "errorType": "Error",
    "errorMessage": "libuuid.so.1: cannot open shared object file: No such file or directory",
    "trace": [
        "Error: libuuid.so.1: cannot open shared object file: No such file or directory",
        "    at Object.Module._extensions..node (internal/modules/cjs/loader.js:730:18)",
        "    at Module.load (internal/modules/cjs/loader.js:600:32)",
        "    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)",
        "    at Function.Module._load (internal/modules/cjs/loader.js:531:3)",
        "    at Module.require (internal/modules/cjs/loader.js:637:17)",
        "    at require (internal/modules/cjs/helpers.js:22:18)",
        "    at Object.<anonymous> (/var/task/node_modules/canvas/lib/bindings.js:3:18)",
        "    at Module._compile (internal/modules/cjs/loader.js:701:30)",
        "    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)",
        "    at Module.load (internal/modules/cjs/loader.js:600:32)",
        "    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)",
        "    at Function.Module._load (internal/modules/cjs/loader.js:531:3)",
        "    at Module.require (internal/modules/cjs/loader.js:637:17)",
        "    at require (internal/modules/cjs/helpers.js:22:18)",
        "    at Object.<anonymous> (/var/task/node_modules/canvas/lib/canvas.js:9:18)",
        "    at Module._compile (internal/modules/cjs/loader.js:701:30)"
    ]
}

Here's how to reproduce it:

1. Spin up an Amazon Linux 2 AMI:

I installed this one. amzn2-ami-hvm-2.0.20190313-x86_64-gp2. Then connect to the server over ssh.

2. Install node 10

curl --silent --location https://rpm.nodesource.com/setup_10.x | sudo bash -
sudo yum install -y nodejs

3. Install Serverless

sudo npm install --global serverless

4. Create project directory and install Canvas

mkdir test && cd test
npm install canvas@2.5.0 --save

5. Create Lambda handler index.js

let {createCanvas} = require("canvas");

function hello(event, context, callback) {
	let
		canvas = createCanvas(200, 200),
		ctx = canvas.getContext('2d');

	// Write "Awesome!"
	ctx.font = '30px Impact';
	ctx.rotate(0.1);
	ctx.fillText('Awesome!', 50, 100);

	// Draw line under text
	let text = ctx.measureText('Awesome!');
	ctx.strokeStyle = 'rgba(0,0,0,0.5)';
	ctx.beginPath();
	ctx.lineTo(50, 102);
	ctx.lineTo(50 + text.width, 102);
	ctx.stroke();

	callback(null, '<img src="' + canvas.toDataURL() + '" />');
}

module.exports = {hello};

6. Create serverless.yml

service: canvas-test

provider:
  name: aws
  runtime: nodejs10.x
  stage: development
  region: us-east-1
  memorySize: 128
  timeout: 10

functions:
  hello:
    handler: index.hello

7. Deploy the function

serverless deploy

8. Invoke the function

serverless invoke --function hello

@thenickdude
Copy link
Contributor

thenickdude commented Jun 7, 2019

For some reason the /lib64 directory on Lambda for Amazon Linux 2 (Node 10) is incredibly sparse, much more empty than in the corresponding AMI they've published, which doesn't make sense to me.

I had to bundle the following libraries from Amazon Linux 2 with my function:

libEGL.so.1
libGL.so.1
libGLX.so.0
libGLdispatch.so.0
libICE.so.6
libSM.so.6
libX11.so.6
libXau.so.6
libXext.so.6
libXrender.so.1
libblkid.so.1
libcairo.so.2
libcroco-0.6.so.3
libexpat.so.1
libfontconfig.so.1
libfreetype.so.6
libfribidi.so.0
libgdk_pixbuf-2.0.so.0
libgif.so.7
libgio-2.0.so.0
libglib-2.0.so.0
libgmodule-2.0.so.0
libgobject-2.0.so.0
libgraphite2.so.3
libgthread-2.0.so.0
libharfbuzz.so.0
libjpeg.so.62
liblzma.so.5
libmount.so.1
libpango-1.0.so.0
libpangocairo-1.0.so.0
libpangoft2-1.0.so.0
libpixman-1.so.0
libpng16.so.16
librsvg-2.so.2
libthai.so.0
libuuid.so.1
libxcb-render.so.0
libxcb-shm.so.0
libxcb.so.1
libxml2.so.2

Notably, libuuid is not even included in the prebuilt Canvas. Is the Amazon Linux 2 image currently deployed on Lambda actually broken?

@jwerre
Copy link

jwerre commented Jun 7, 2019

@thenickdude libuuid is included on my AMI

ll /usr/lib64/ | grep libuuid
lrwxrwxrwx  1 root root       16 Mar  8 19:58 libuuid.so.1 -> libuuid.so.1.3.0
-rwxr-xr-x  1 root root    20056 Jul 26  2018 libuuid.so.1.3.0

What is that size of all that? Copying all these files into your project will put you dangerously close the the max size of a Lambda function (250 MB).

@thenickdude
Copy link
Contributor

thenickdude commented Jun 7, 2019

Yes, it's in the AMI but it's not in the actual Lambda runtime environment. Run this on Lambda Node 10.x:

const fs = require('fs');

exports.handler = async (event, context) => {
  return fs.readdirSync("/usr/lib64").filter(p => p.match(/\.so/)).sort().join("\n");
};

This is the result:

ld-2.26.so
ld-linux-x86-64.so.2
libBrokenLocale-2.26.so
libBrokenLocale.so.1
libSegFault.so
libacl.so.1
libacl.so.1.1.0
libanl-2.26.so
libanl.so.1
libattr.so.1
libattr.so.1.1.0
libc-2.26.so
libc.so.6
libcap.so.2
libcap.so.2.22
libcidn-2.26.so
libcidn.so.1
libcom_err.so.2
libcom_err.so.2.1
libcrypto.so.1.0.2k
libcrypto.so.10
libdl-2.26.so
libdl.so.2
libffi.so.6
libffi.so.6.0.1
libform.so.6
libform.so.6.0
libformw.so.6
libformw.so.6.0
libfreebl3.chk
libfreebl3.so
libfreeblpriv3.chk
libfreeblpriv3.so
libgcc_s-7-20180303.so.1
libgcc_s.so.1
libgmp.so.10
libgmp.so.10.2.0
libgmpxx.so.4
libgmpxx.so.4.4.0
libgssapi_krb5.so.2
libgssapi_krb5.so.2.2
libgssrpc.so.4
libgssrpc.so.4.2
libk5crypto.so.3
libk5crypto.so.3.1
libkdb5.so.8
libkdb5.so.8.0
libkeyutils.so.1
libkeyutils.so.1.5
libkrad.so.0
libkrad.so.0.0
libkrb5.so.3
libkrb5.so.3.3
libkrb5support.so.0
libkrb5support.so.0.1
libm-2.26.so
libm.so.6
libmemusage.so
libmenu.so.6
libmenu.so.6.0
libmenuw.so.6
libmenuw.so.6.0
libmvec-2.26.so
libmvec.so.1
libncurses.so.6
libncurses.so.6.0
libncursesw.so.6
libncursesw.so.6.0
libnsl-2.26.so
libnsl.so.1
libnspr4.so
libnss_compat-2.26.so
libnss_compat.so.2
libnss_dns-2.26.so
libnss_dns.so.2
libnss_files-2.26.so
libnss_files.so.2
libnssckbi.so
libnssutil3.so
libp11-kit.so.0
libp11-kit.so.0.3.0
libpanel.so.6
libpanel.so.6.0
libpanelw.so.6
libpanelw.so.6.0
libpcprofile.so
libpcre.so.1
libpcre.so.1.2.0
libpcre16.so.0
libpcre16.so.0.2.0
libpcre32.so.0
libpcre32.so.0.0.0
libpcrecpp.so.0
libpcrecpp.so.0.0.0
libpcreposix.so.0
libpcreposix.so.0.0.1
libplc4.so
libplds4.so
libpopt.so.0
libpopt.so.0.0.0
libpthread-2.26.so
libpthread.so.0
libresolv-2.26.so
libresolv.so.2
librt-2.26.so
librt.so.1
libselinux.so.1
libsepol.so.1
libssl.so.1.0.2k
libssl.so.10
libstdc++.so.6
libstdc++.so.6.0.24
libtasn1.so.6
libtasn1.so.6.5.3
libthread_db-1.0.so
libthread_db.so.1
libtic.so.6
libtic.so.6.0
libtinfo.so.6
libtinfo.so.6.0
libutil-2.26.so
libutil.so.1
libverto.so.1
libverto.so.1.0.0
libz.so.1
libz.so.1.2.7
p11-kit-proxy.so
p11-kit-trust.so

The required libraries from my last post are about 100MB.

@jwerre
Copy link

jwerre commented Jun 27, 2019

@thenickdude Thanks for your insight on this. I created a Lambda Layer which will address this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests