问题
Motivation for doing this approach in the first place comes from Amazon: https://aws.amazon.com/blogs/compute/resize-images-on-the-fly-with-amazon-s3-aws-lambda-and-amazon-api-gateway/ (before they added the 'update'...)
In our AWS Lambda resize function it resizes the image and stores it the new image on S3.
const s3_bucket = process.env.s3_bucket;
S3.putObject({
Body: buffer,
Bucket: s3_bucket,
ContentType: contentType,
CacheControl: 'max-age=31536000',
Key: key,
StorageClass: 'STANDARD'
}).promise()
Now we want this to work for all our test/staging environments as well as production.. So I found "Environment Variables", I though great! But when I try to deploy a new version all I get is:
Have we set up something incorrectly in CloudFront? We are using Node version 6.10. I find it hard to believe if we have to hardcode the buckets and keep different versions of the code just to handle this? If that is the case then we wasted a lot of time using AWS Lambda...
Edit: What we do is take a request for an image like "media/catalog/product/3/0/30123/768x/lorem.jpg", then we use the original image located at "media/catalog/product/3/0/30123.jpg", resize it to 768px and webp if the browser supports that and then return the new image (if not already cached).
回答1:
Workaround using custom origin headers
Environment variables are not supported by Lambda@Edge as specified in the limitations documentation.
But if you are using Lambda@Edge either on origin request or origin response, you can use a workaround with CloudFront Origin Custom Headers.
Basically instead of environment variable, you can set custom headers within your CloudFront origin. Those "static" headers will then be passed to your origin request/response Lambda@Edge.
Then you can access them in your Lambda@Edge function code via:
const foo = request.origin.custom.customHeaders["x-env-foo"][0].value;
Or when using S3 as the origin:
const foo = request.origin.s3.customHeaders["x-env-foo"][0].value;
See also https://medium.com/@mnylen/lambda-edge-gotchas-and-tips-93083f8b4152
回答2:
As mentioned in this documentation for CloudFront Lambda limitations:
Environment variables aren't supported.
What you could do instead is use SSM Parameter Store to manage your function's variables. You can edit Parameter Store variables through the console or programmatically, and you can get the variables using the ssm.getParameter() function
回答3:
I had this as a comment but I think it's worth adding it as an answer.
Why do you need to use Lambda@Edge to begin with? I understand your frustration, but Lambda@Edge was designed to achieve a completely different set of things. See some use cases here
In your use case, you upload an object to S3 and the PUT object event will trigger your Lambda function, which is, by nature, asynchronous and eventual consistent. Your users really don't need the optimised thumbnail generation execution time since you'd only be gaining a few hundreds of milliseconds anyways. By the time they need the thumbnail, it will already be there regardless.
In regular Lambda functions, you can absolutely make use of environment variables, making it very easy to apply different settings to different environments (dev, test, prod).
You can see how to set environment variables in regular Lambda Functions here
回答4:
I solved it by prepending the s3_bucket
to the js file in the bash build script. So I specify build.sh [s3_bucket] [environment-name]
if [ ! $# -eq 2 ]; then
echo 'You need to provide two parameters: [s3_bucket] [environment]'
echo 'example: build.sh imagetest-us-east-1 next'
echo 'example: build.sh [s3_bucket_to_be_defined] production'
exit 1
fi
filename='index.js'
setCurrentEnvironment() {
jsEnv="const s3_bucket='$1';"
mv "$filename" "$filename".orig && cp "$filename".orig "$filename"
echo -e "$jsEnv\n\n$(cat ${filename})" > "$filename"
}
restoreDefault() {
rm -rf "$filename"
mv "$filename".orig "$filename"
}
setCurrentEnvironment $1
zip -FS -q -r "../../dist/resize__$2.zip" *
restoreDefault
回答5:
As an alternative to the selected answer...
The same could be achieved using the Serverless Framework, Webpack and the serverless-webpack plugin.
You can access options used for the serverless operation with:
const slsw = require('serverless-webpack');
const stage = slsw.lib.options.stage;
Or, you can access information in the serverless.yml
file with:
const serverless = slsw.lib.serverless;
Then simply add this to the plugins of your webpack.config.js
file:
plugins: [new EnvironmentPlugin({ VAR1: var1, VAR2: var2, STAGE: stage })]
This method can provide you with an easy way to manage environment variables in Lambda@Edge functions - read the case studies to see why the Serverless Framework is great.
来源:https://stackoverflow.com/questions/54828808/aws-lambdaedge-nodejs-environment-variables-are-not-supported