|
| 1 | +How to run NightmareJS on AWS Lambda |
| 2 | +===== |
| 3 | + |
| 4 | + |
| 5 | +In order to help you running NightmareJS o AWS Lambda we have created this package. |
| 6 | + |
| 7 | +First clone the package into your home directory. |
| 8 | + |
| 9 | + |
| 10 | +``` |
| 11 | +git clone http://github.com/dimkir/nightmare-lambda-tutorial.git |
| 12 | +cd nightmare-lambda-tutorial |
| 13 | +``` |
| 14 | + |
| 15 | + |
| 16 | + |
| 17 | +#### Install and configure AWS CLI |
| 18 | + |
| 19 | +Before we are able to create You have to have AWS CLI installed |
| 20 | +``` |
| 21 | +sudo pip install awscli |
| 22 | +
|
| 23 | +aws configure |
| 24 | +
|
| 25 | +``` |
| 26 | + |
| 27 | +Make sure that you can execute under user credentials which have at least Admin Policy |
| 28 | +(because creating Lambda Function requires creating IAM role and only Admin Policy can do that). |
| 29 | + |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | +#### Choose your function/project name |
| 35 | + |
| 36 | +When your lambda function is published on AWS it should have a name. Please edit file `projectname.txt` and set |
| 37 | +the contents of the file to what you want your lambda called (remember to only use alphanumerical values and underscore). |
| 38 | +Or you can leave default name `nightmare-tutorial`. |
| 39 | + |
| 40 | + |
| 41 | + |
| 42 | +#### Create your AWS Lambda function |
| 43 | + |
| 44 | +There's a lot of ways to create lambda function: by clicking through AWS Web console, using AWS CLI or use the helper scripts from `bin/` directory. |
| 45 | + |
| 46 | +First let's call |
| 47 | + |
| 48 | +``` |
| 49 | +[nightmare-lambda-tutorial]$ bin/install/create-function.sh |
| 50 | +
|
| 51 | +``` |
| 52 | + |
| 53 | + |
| 54 | +You will get similar looking help output, which suggest that as a second parameter, |
| 55 | +we should use id (ARN) of the role under which lambda function will be executed. |
| 56 | + |
| 57 | +``` |
| 58 | +20:02 $ bin/install/create-function.sh |
| 59 | +Number of parameters is 0 |
| 60 | +
|
| 61 | + Usage: |
| 62 | +
|
| 63 | + ./create-function.sh <function-name-or-alias> <role-arn> <function-package.zip> |
| 64 | +
|
| 65 | + Example: |
| 66 | +
|
| 67 | + ./create-function.sh nightmare-tutorial arn:xxxx var/dist/nightmare-tutorial.zip |
| 68 | +
|
| 69 | +``` |
| 70 | + |
| 71 | + |
| 72 | +In order to get id (ARN) of the role, we first have to create this role. |
| 73 | + |
| 74 | +Let's use another utility - `bin/install/create-role-with-policy.sh`: |
| 75 | + |
| 76 | +``` |
| 77 | +✘-1 ~/l/nightmare-tutorial [master L|…14] |
| 78 | +20:02 $ bin/install/create-role-with-policy.sh |
| 79 | +Number of parameters is 0 |
| 80 | +
|
| 81 | +--------------------------------------------- |
| 82 | +Utility for creating lambda functions. |
| 83 | +Creates a role for a particular function name, |
| 84 | +and adds policy to read from source bucket and write to target bucket. |
| 85 | +---------------------------------------------- |
| 86 | +
|
| 87 | +
|
| 88 | +Usage: |
| 89 | + ./create-role-with-policy.sh <function-name-or-alias> <source_bucket> <target_bucket> |
| 90 | +
|
| 91 | +
|
| 92 | +
|
| 93 | +
|
| 94 | +``` |
| 95 | + |
| 96 | + |
| 97 | +The source code from this tutorial will take a screenshot of a website using Nightmare and will save it to S3, |
| 98 | +this is why we need to specify buckets which lambda function will be able to read and write. |
| 99 | + |
| 100 | +So go ahead and create a bucket (manually or via `aws s3 mb s3://my-fancy-bucket-777 --region eu-west-1`) and once |
| 101 | +the bucket is ready let's create a role: |
| 102 | + |
| 103 | + |
| 104 | +``` |
| 105 | +bin/install/create-role-with-policy.sh nightmare-tutorial my-fancy-bucket-777 my-fancy-bucket-777 |
| 106 | +``` |
| 107 | + |
| 108 | +You will get output similar to this, what is important for us is arn of the role: |
| 109 | +`arn:aws:iam::326625058526:role/lambda-nightmare-tutorial-execution-role` |
| 110 | + |
| 111 | + |
| 112 | +``` |
| 113 | +✔ ~/l/nightmare-tutorial [master L|…14] |
| 114 | +20:12 $ bin/install/create-role-with-policy.sh nightmare-tutorial my-fancy-bucket-777 my-fancy-bucket-777 |
| 115 | +Number of parameters is 3 |
| 116 | +Lambda function alias: [nightmare-tutorial2], source bucket [my-fancy-bucket-777], target bucket: [my-fancy-bucket-777] |
| 117 | +lambda_execution_role_arn=arn:aws:iam::326625058526:role/lambda-nightmare-tutorial-execution-role |
| 118 | +
|
| 119 | +``` |
| 120 | + |
| 121 | + |
| 122 | + |
| 123 | +Before we make a function, we have create a zip package. In simple words we will include the source files |
| 124 | +and most of dependencies from `node_modules` folder. For running on Lambda we will not need `electron/dist` folder |
| 125 | +and it will be excluded from the archive. For more details on how package is zipped see `bin/zip-package.sh`. |
| 126 | + |
| 127 | +``` |
| 128 | +bin/zip-package.zip |
| 129 | +``` |
| 130 | + |
| 131 | +You will see the list of files added to the package and total size of the zip. In my case it is ~1Mb. |
| 132 | +The zip-will be stored in the folder `var/dist`. |
| 133 | + |
| 134 | +``` |
| 135 | + adding: ..... |
| 136 | + adding: ..... |
| 137 | + adding: ..... |
| 138 | + adding: ..... |
| 139 | + adding: ..... |
| 140 | +
|
| 141 | +-rw-rw-r-- 1 mars mars 1.1M Mar 13 20:21 var/dist/nightmare-tutorial.zip |
| 142 | +
|
| 143 | +``` |
| 144 | + |
| 145 | + |
| 146 | +Now, as we finally have role ID (ARN) and zipped function source, we can finally create our function. We choose `nodejs4.3` runtime |
| 147 | +and create function with 1024Mb of Memory (they work and boot up faster and it is rarely worth using lambdas with less memory). |
| 148 | + |
| 149 | +``` |
| 150 | +[nightmare-lambda-tutorial]$ bin/install/create-function.sh nightmare-tutorial \ |
| 151 | + arn:aws:iam::326625058526:role/lambda-nightmare-tutorial-execution-role \ |
| 152 | + var/dist/nightmare-tutorial.zip |
| 153 | +``` |
| 154 | + |
| 155 | + |
| 156 | +``` |
| 157 | +✔ ~/l/nightmare-tutorial [master L|…14] |
| 158 | +20:24 $ bin/install/create-function.sh nightmare-tutorial arn:aws:iam::326625058526:role/lambda-nightmare-tutorial-execution-role var/dist/nightmare-tutorial.zip |
| 159 | +Number of parameters is 3 |
| 160 | +Function alias:\t nightmare-tutorial |
| 161 | +Role ARN: \t arn:aws:iam::326625058526:role/lambda-nightmare-tutorial2-execution-role |
| 162 | +Function package:\t var/dist/nightmare-tutorial.zip |
| 163 | +{ |
| 164 | + "CodeSha256": "QedKlzWH0A9jPumkuuyleINFDNdqkqANy9hA2ysjoUA=", |
| 165 | + "FunctionName": "nightmare-tutorial", |
| 166 | + "CodeSize": 1062573, |
| 167 | + "MemorySize": 1024, |
| 168 | + "FunctionArn": "arn:aws:lambda:eu-west-1:326625058526:function:nightmare-tutorial", |
| 169 | + "Version": "$LATEST", |
| 170 | + "Role": "arn:aws:iam::326625058526:role/lambda-nightmare-tutorial-execution-role", |
| 171 | + "Timeout": 3, |
| 172 | + "LastModified": "2017-03-13T20:24:43.112+0000", |
| 173 | + "Handler": "index.handler", |
| 174 | + "Runtime": "nodejs4.3", |
| 175 | + "Description": "" |
| 176 | +} |
| 177 | +
|
| 178 | +
|
| 179 | +``` |
| 180 | + |
| 181 | + |
| 182 | + |
| 183 | +#### Run your lambda function |
| 184 | + |
| 185 | +Now you can invoke your lambda function either by calling `bin/run.sh http://www.yahoo.com`. |
| 186 | +If you have configured everything correctly, you will see similar output. |
| 187 | + |
| 188 | +``` |
| 189 | +20:24 $ bin/run.sh http://www.yahoo.com |
| 190 | +{ |
| 191 | + "StatusCode": 200 |
| 192 | +} |
| 193 | +Returned with retval [0] |
| 194 | +"http://s3-eu-west-1.amazonaws.com/my-fancy-bucket-777/test/store/image-1489436927266.png" |
| 195 | +JQ returned 0 |
| 196 | +✔ ~/l/nightmare-tutorial [master L|…14] |
| 197 | +
|
| 198 | +``` |
| 199 | + |
| 200 | + |
| 201 | + |
| 202 | + |
| 203 | + |
| 204 | +or if you prefer to invoke the lambda manually, you can do that via AWS CLI. Note that last parameter |
| 205 | +is the name of the log file (no need for output redirects like `>`!). And to see the result you would have to `cat var/log/logfile.txt` |
| 206 | + |
| 207 | +``` |
| 208 | +aws lambda invoke-function \ |
| 209 | + --function-name nightmare-tutorial \ |
| 210 | + --payload '{ "url" : "http://www.yahoo.com" }' \ |
| 211 | + var/log/logfile.txt |
| 212 | +
|
| 213 | +``` |
| 214 | + |
| 215 | + |
| 216 | + |
| 217 | + |
| 218 | + |
| 219 | + |
| 220 | + |
| 221 | +#### Let's review the magic which allows nightmare to run |
| 222 | + |
| 223 | +In the very header of `index.js` you can find the following code, |
| 224 | +which takes care of pulling and installing all required native dependencies: |
| 225 | + |
| 226 | + |
| 227 | +``` |
| 228 | +/*********************************************************** |
| 229 | + * This magic code runs once per boot-up of lambda container |
| 230 | + * and pulls all the electron and Xvfb binaries and stores |
| 231 | + * them in /tmp/pck folder. |
| 232 | + * |
| 233 | + * Later on business logic should be called within xvfb.start() |
| 234 | + * callback, so that when Nightmare calls Electron there is |
| 235 | + * a virtual framebuffer available. |
| 236 | + * |
| 237 | + * Variable electronPath starts as undefined and is only |
| 238 | + * overridden on Lambda environment. Which simplifies testing |
| 239 | + * lambda in local environment. |
| 240 | + * |
| 241 | + ***********************************************************/ |
| 242 | +console.log('Lambda executes global code upon container boot-up'); |
| 243 | +
|
| 244 | +var electronPath, pack, isOnLambda, Xvfb; |
| 245 | +
|
| 246 | +pack = require('./lib/bootstrap/nightmare-lambda-pack'); |
| 247 | +isOnLambda = pack.isOnLambda; |
| 248 | +Xvfb = require('./lib/bootstrap/xvfb'); |
| 249 | +if ( isOnLambda ){ |
| 250 | + electronPath = pack.installNightmare(); |
| 251 | +} |
| 252 | +
|
| 253 | +
|
| 254 | +/** ************************************************************** */ |
| 255 | +
|
| 256 | +
|
| 257 | +``` |
| 258 | + |
| 259 | + |
| 260 | +Also business logic is running within callback to `xvfb.start()` |
| 261 | +which allows to start using Nightmare/Electron only when virtual framebuffer is available. |
| 262 | + |
| 263 | + |
| 264 | + |
| 265 | + |
0 commit comments