silvermine / serverless-plugin-cloudfront-lambda-edge

Adds Lambda@Edge support to Serverless
MIT License
296 stars 41 forks source link

Question: use a distribution ID as the distribution? #14

Closed marcelpanse closed 6 years ago

marcelpanse commented 6 years ago

Hi, We have a situation where are already using AWS extensively (lambda, edge, apig, s3, cf, etc). We are now moving to the serverless framework instead of apex that we used so far. We migrated all the lambda's already which is working fine, now we want to deploy the edge functions using serverless. However, I can only reference a defined cloudformation distribution name as the distribution of the function. This is not an option for us, since our CF is fairly complicated with 50 behaviors and multiple origins. I don't want to configure all of that in serverless at this moment, also I think this is not possible without deploying an entirely new CF distribution (which would mean we lose cache hits, etc).

Anyway, I was wondering if we could just use a distribution ID in the distribution field instead? Is there a reason why this shouldn't or can't be done? If not, I could make a PR.

jthomerson commented 6 years ago

@marcelpanse the first version of this plugin (the only one currently released could've been updated to do this because it was manually updating the distribution after the distribution had been deployed by CloudFormation. That was never the desired behavior, though, because it resulted in two deploys of the distribution - the first one by CloudFormation, and then the second as a result of the update to update the Lambda@Edge associations. As you know, CloudFront distribution deployments are among the slowest resources you can deploy - for me they seem to generally take about thirty minutes for each change.

The second version of the plugin (in development in a "v2.0-wip" branch, and nearly complete), works the way the plugin would've worked originally if CloudFormation had support for Lambda@Edge - it simply updates the CloudFormation stack template that Serverless creates, adding the Lambda@Edge associations to the CloudFront distribution so that they are deployed by CloudFormation in a single deployment. The plugin also does two other things: 1) remove any environment variables from the Lambda function definition in the CF stack template, and 2) update the role that the Lambda function will run as so that it has permission to create its own log groups.

So, because the plugin works (in the upcoming v2) by making changes to your CloudFormation template for the CloudFront distribution, it's not possible to use it on a CloudFront distribution that's made in another stack.

However: If you're making your Lambda functions in one stack and your CloudFront distribution(s) in another stack, you probably don't need this plugin, although you might need to write a very simple plugin (perhaps just a local plugin to do a couple things.

The basic design would be:

  1. Stack one is your serverless stack - it deploys your Lambda functions
  2. Stack two is your straight CloudFormation stack - it deploys your CloudFront distribution

In stack one, you just need to make sure that:

  1. The Lambda functions: a. are versioned b. don't have any environment variables c. have permission to create log groups, etc (see this code as an example)
  2. The stack containing the Lambda functions exports a reference to the function version in the stack outputs. a. Serverless already creates the stack output for you - it just doesn't assign it an export name. This is where the simple plugin comes in - write a plugin like the one we have here (that operates on the completed stack template before it's written to disk), and simply find those outputs and add an export name to them. You may use the plugin to do the other modifications that this plugin does - strip env vars and add perms to the role - if you want, although you should be able to control both of those in your serverless template.
  3. The stack containing the CloudFront distribution, then, could reference the exported lambda function versions directly using Fn::ImportValue in its LambdaFunctionAssociations.

Hope that helps.

marcelpanse commented 6 years ago

I think it could be much simpler. The CF distro we have is not in any stack, it was just manually added. If it is not possible to reference a distribution by ID like you explained, then a simpler solution would be to just not associate the function automatically with CF. Basically, I just want to deploy the function, manually test it, and then associate it manually with the CF distro. I think this could be achieved with your plugin by simply adding an option to not associate the edge function (not call _handleSingleFunctionAssociation() ?)

Does that make sense to add as an option?

jthomerson commented 6 years ago

Okay, so basically using the plugin just to do the env vars stripping and the role updating. We'll give that some thought.

shaunc commented 6 years ago

It seems that both creating a distribution together with lambda functions and updating an existing distribution by modifying lambda functions are useful behaviors. (I ended up using this to learn how to configure my distribution and lambda functions to use lambda@edge because there are a number of gotchas for the newbie like myself.) Perhaps updating existing could be an alternate behavior of the plugin?

jthomerson commented 6 years ago

Sorry guys, closing this issue. I believe strongly in the single responsibility principle. This plugin's single responsibility is - as its name indicates - to make Lambda functions work with Lambda@Edge, with CloudFront. The entire plugin is 163 lines of code; part of the reason it's so simple is because it only does one thing, and does it well.

There's a lot of explanation above about how you could make a plugin targeting your specific usecases. You can fork this one, rename it, and use it as a base, or copy and paste the code from either v1 or v2 of this plugin into your own.

ossareh commented 6 years ago

@marcelpanse & @shaunc I too had a similar challenge; specifically I don't yet have the operational confidence in serverless to know what will inadvertently re-create a set of resources - in the case of a CloudFront distribution that takes so long, and causes some many knock on issues that while this plugin does much of what I want, it doesn't do it all.

As such I created my own based on the feedback in the first comment from @jthomerson : https://github.com/ossareh/serverless-lambda-edge - it's not being published to npm yet (happy to take PR's on that). In short you sls deploy --stage production and then aws cloudformation --region us-east-1 list-exports - take the arn and use it in your CloudFront distribution (which I manage in CloudFront away from serverless).