带有 AWS lambda 的 Terraform

Posted

技术标签:

【中文标题】带有 AWS lambda 的 Terraform【英文标题】:Terraform with AWS lamda 【发布时间】:2021-05-15 19:14:36 【问题描述】:

我真的找不到任何与我的问题相关的内容。我正在创建一个 Tf 脚本,它将触发 lambda、cloudwatch 事件和 IAM 以在我的环境中停止和启动一些 ec2。请参阅下面的代码,请让我知道我做错了什么!

main.tf

#
# Test 
#

provider "aws" 
    region = "us-gov-west-1"
    shared_credentials_file = "~/.aws/credentials"
    profile                 = "default"



resource "aws_iam_policy" "stop_start_ec2_policy" 
  name = "StopStartEC2Policy"
  path = "/"
  description = "IAM policy for stop and start EC2 from a lambda"

  policy = <<EOF

  "Version": "2012-10-17",
  "Statement": [
    
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws-us-gov:logs:*:*:*"
    ,
    
      "Effect": "Allow",
      "Action": [
        "ec2:Start*",
        "ec2:Stop*",
        "ec2:DescribeInstances*"
      ],
      "Resource": "*"
    
  ]

EOF


resource "aws_iam_role" "stop_start_ec2_role" 
  name = "StopStartEC2Role"

  assume_role_policy = <<EOF

  "Version": "2012-10-17",
  "Statement": [
    
      "Action": "sts:AssumeRole",
      "Principal": 
        "Service": "lambda.amazonaws.com"
      ,
      "Effect": "Allow",
      "Sid": ""
    
  ]

EOF


resource "aws_iam_role_policy_attachment" "lambda_role_policy" 
  role = "$aws_iam_role.stop_start_ec2_role.name"
  policy_arn = "$aws_iam_policy.stop_start_ec2_policy.arn"


resource "aws_lambda_function" "stop_ec2_lambda" 
  filename      = "ec2_lambda_handler.zip"
  function_name = "stopEC2Lambda"
  role          = "$aws_iam_role.stop_start_ec2_role.arn"
  handler       = "ec2_lambda_handler.stop"
  source_code_hash = "$filebase64sha256("ec2_lambda_handler.zip")"

  runtime = "python3.7"
  memory_size = "250"
  timeout = "60"


resource "aws_cloudwatch_event_rule" "ec2_stop_rule" 
  name        = "StopEC2Instances"
  description = "Stop EC2 nodes at 19:00 from Monday to friday"
  schedule_expression = "cron(0 19 ? * 2-6 *)"


resource "aws_cloudwatch_event_target" "ec2_stop_rule_target" 
  rule      = "$aws_cloudwatch_event_rule.ec2_stop_rule.name"
  arn       = "$aws_lambda_function.stop_ec2_lambda.arn"


resource "aws_lambda_permission" "allow_cloudwatch_stop" 
  statement_id  = "AllowExecutionFromCloudWatch"
  action        = "lambda:InvokeFunction"
  function_name = "$aws_lambda_function.stop_ec2_lambda.function_name"
  principal     = "events.amazonaws.com"


resource "aws_lambda_function" "start_ec2_lambda" 
  filename      = "ec2_lambda_handler.zip"
  function_name = "startEC2Lambda"
  role          = "$aws_iam_role.stop_start_ec2_role.arn"
  handler       = "ec2_lambda_handler.start"
  source_code_hash = "$filebase64sha256("ec2_lambda_handler.zip")"

  runtime = "python3.7"
  memory_size = "250"
  timeout = "60"


resource "aws_cloudwatch_event_rule" "ec2_start_rule" 
  name        = "StartEC2Instances"
  description = "Start EC2 nodes at 6:30 from Monday to friday"
  schedule_expression = "cron(30 6 ? * 2-6 *)"


resource "aws_cloudwatch_event_target" "ec2_start_rule_target" 
  rule      = "$aws_cloudwatch_event_rule.ec2_start_rule.name"
  arn       = "$aws_lambda_function.start_ec2_lambda.arn"


resource "aws_lambda_permission" "allow_cloudwatch_start" 
  statement_id  = "AllowExecutionFromCloudWatch"
  action        = "lambda:InvokeFunction"
  function_name = "$aws_lambda_function.start_ec2_lambda.function_name"
  principal     = "events.amazonaws.com"

我的 ec2_lambda_handler.py

import boto3
region = 'eu-central-1'
ec2 = boto3.client('ec2', region_name=region)
response = ec2.describe_instances(Filters=[
        
            'Name': 'tag:Auto-Start',
            'Values': [
                'true',
            ]
        ,
    ])

instances = []

for reservation in response["Reservations"]:
    for instance in reservation["Instances"]:
        instances.append(instance["InstanceId"])

def stop(event, context):
    ec2.stop_instances(InstanceIds=instances)
    print('stopped instances: ' + str(instances))

def start(event, context):
    ec2.start_instances(InstanceIds=instances)
    print('started  instances: ' + str(instances))

我得到的错误:

Plan: 11 to add, 0 to change, 0 to destroy.


Warning: Interpolation-only expressions are deprecated

  on main.tf line 65, in resource "aws_iam_role_policy_attachment" "lambda_role_policy":
  65:   role = "$aws_iam_role.stop_start_ec2_role.name"

Terraform 0.11 and earlier required all non-constant expressions to be
provided via interpolation syntax, but this pattern is now deprecated. To
silence this warning, remove the "$ sequence from the start and the "
sequence from the end of this expression, leaving just the inner expression.

Template interpolation syntax is still used to construct strings from
expressions when the template includes multiple interpolation sequences or a
mixture of literal strings and interpolations. This deprecation applies only
to templates that consist entirely of a single interpolation sequence.

(and 9 more similar warnings elsewhere)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_iam_policy.stop_start_ec2_policy: Creating...
aws_cloudwatch_event_rule.ec2_start_rule: Creating...
aws_iam_role.stop_start_ec2_role: Creating...
aws_cloudwatch_event_rule.ec2_stop_rule: Creating...
aws_iam_role.stop_start_ec2_role: Creation complete after 1s [id=StopStartEC2Role]
aws_lambda_function.stop_ec2_lambda: Creating...
aws_lambda_function.start_ec2_lambda: Creating...
aws_cloudwatch_event_rule.ec2_start_rule: Creation complete after 2s [id=StartEC2Instances]
aws_cloudwatch_event_rule.ec2_stop_rule: Creation complete after 2s [id=StopEC2Instances]
aws_iam_policy.stop_start_ec2_policy: Creation complete after 2s [id=arn:aws-us-gov:iam::235856440647:policy/StopStartEC2Policy]
aws_iam_role_policy_attachment.lambda_role_policy: Creating...
aws_iam_role_policy_attachment.lambda_role_policy: Creation complete after 0s [id=StopStartEC2Role-20210211225204032900000001]

Error: Unable to load "ec2_lambda_handler.zip": open ec2_lambda_handler.zip: no such file or directory

我的目录:

$ ls 
ec2_lambda_handler.py  main.tf

我感觉在 Terraform 运行之前 zip 文件不存在,但不知道如何解决这个问题!!请帮忙!!!!这里是源代码:https://medium.com/better-programming/minimize-the-costs-of-running-aws-ec2-instances-using-terraform-3999c5141830

【问题讨论】:

你使用什么版本的 terraform? 对不起,我错过了Terraform v0.13.4 【参考方案1】:

您根本没有创建 zip。你只有ec2_lambda_handler.py。通常你会在使用 lambda 函数之前使用archive_file 对其进行压缩:

data "archive_file" "zip" 
       type        = "zip"
       source_file = "ec2_lambda_handler.py"
       output_path = "ec2_lambda_handler.zip"

然后在你的 lambda 中:

resource "aws_lambda_function" "stop_ec2_lambda" 
  filename         = data.archive_file.zip.output_path
  function_name    = "stopEC2Lambda"
  role             = "$aws_iam_role.stop_start_ec2_role.arn"
  handler          = "ec2_lambda_handler.stop"
  source_code_hash =  data.archive_file.zip.output_base64sha256

  runtime = "python3.7"
  memory_size = "250"
  timeout = "60"

【讨论】:

Marcin 你是个救命稻草 ;)【参考方案2】:

这是我用的:

resource "aws_lambda_function" "lambda" 
  filename                      = "deployment-files/lambda_logs/file.zip"
  function_name                 = "$var.teamid-$var.prjid"
  role                          = var.role
  handler                       = var.handler
  source_code_hash              = base64sha256("file.zip")

  runtime                       = var.runtime == "" ? "null" :  var.runtime
  memory_size                   = var.memory_size == "" ? "null" :  var.memory_size
  timeout                       = var.timeout == "" ? "null" :  var.timeout
  description                   = var.description == "" ? "null" :  var.description

  tags                          = merge(local.shared_tags)

  environment 
    variables                   = var.environment_vars
  


其中 payload_file本地 zipfile 路径 并且 source_code_hash 是 lambda 中的文件名

【讨论】:

以上是关于带有 AWS lambda 的 Terraform的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 AWS Lambda 脚本通过 Terraform 部署 AWS 基础设施

使用 Terraform 将 AWS Lambda 日志写入 CloudWatch 日志组

如何将 AWS cloudwatch 事件添加到基于具有 terraform 的容器映像的 aws_lambda_function?

schedult 上的 aws 自定义事件以触发 lambda 使用 Terraform

terraform/aws lambda 函数访问在 s3 上被拒绝

Terraform:为调用 Lambda 的 AWS API Gateway 创建 url 路径参数?