Terraform 进阶 - 部署 Lambda 并创建相关资源

昨日刚刚体验了 Terraform 是一个什么鬼东西 Terraform 使用 - 从最简单例子开始,今天再进一步。将来尝试的是使用 Terraform 来部署一个 Lambda 应用,并创建相关的资源。


本例中的 Lambda 要由 Kinesis 来触发,并写数据到 S3 Bucket 中去,所以需要做的事情大致如下:
  1. 创建 IAM Role, 该 Role 要能访问 S3, Kinesis 和 CloudWatch
  2. 创建一个 Kinesis Stream (指定 Shard 数目)
  3. 创建一个 S3 Bucket
  4. 部署 Lambda (要指定能访问 S3 Bucket 的 Role, 并其他参数,如环境变量)
  5. 设置 Lambda 的 Kinesis 触发器 (指定源 Kinesis Stream 和  batchSize)

以下是 Lambda 的实现代码,从 Kinesis 读出字符串,逗号分割,第一部分作为 S3 Key, 第二部分作为文件内容写入到 S3 Bucket 中去。S3 Bucket 名称从环境变量中读取。
 1public class Handler implements RequestHandler<KinesisEvent, String> {
 2
 3    @Override
 4    public String handleRequest(KinesisEvent event, Context context) {
 5        LambdaLogger logger = context.getLogger();
 6        event.getRecords().forEach(record -> {
 7            String data = new String(record.getKinesis().getData().array());
 8            logger.log("Received data: " + data);
 9
10            String[] keyAndContent = data.split(",");
11            ObjectMetadata objectMetadata = new ObjectMetadata();
12            objectMetadata.setContentLength(keyAndContent[1].getBytes().length);
13            AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient();
14            s3Client.putObject(System.getenv("BUCKET_NAME"), keyAndContent[0],
15                new ByteArrayInputStream(keyAndContent[1].getBytes()), objectMetadata);
16        });
17        return null;
18    }
19}

接下来的事情全部要交给 Terraform 来完成了,在于怎么写那个 tf 文件,为方便起见我们直接在这个 Java 项目根目录下创建一个  main.tf 文件。
 1provider "aws" {
 2  region                  = "us-east-1"
 3  shared_credentials_file = "/Users/Yanbin/.aws/credentials" //默认就是 ~/.aws/credentials
 4  profile                 = "yanbin"                         //默认是 default
 5}
 6
 7resource "aws_s3_bucket" "test-bucket" {
 8  bucket = "yanbin-test-bucket"
 9  acl    = "private"
10
11  tags {
12    Environment = "test"
13  }
14}
15
16//resource 后第二个字符串 name "test-stream" 还是很有用的,后面引用就靠它
17resource "aws_kinesis_stream" "test-stream" {
18  name        = "yanbin-test-stream"
19  shard_count = 2
20
21  tags {
22    Environment = "test"
23  }
24}
25
26resource "aws_iam_role" "role_for_lambda" {
27  name = "yanbin_lambda_role"
28
29  //特别要注意这里的格式 <<EOF 是一整体,其中的 JSON 在下行一定要顶格写
30  assume_role_policy = <<EOF
31{
32  "Version": "2012-10-17",
33  "Statement": [
34    {
35      "Action": "sts:AssumeRole",
36      "Principal": {
37        "Service": "lambda.amazonaws.com"
38      },
39      "Effect": "Allow",
40      "Sid": ""
41    }
42  ]
43}
44EOF
45}
46
47resource "aws_iam_role_policy_attachment" "s3-access-policy-attachment" {
48  role       = "${aws_iam_role.role_for_lambda.name}"
49  policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
50}
51
52resource "aws_iam_role_policy_attachment" "kinesis-access-policy-attachment" {
53  role       = "${aws_iam_role.role_for_lambda.name}"
54  policy_arn = "arn:aws:iam::aws:policy/AmazonKinesisFullAccess"
55}
56
57resource "aws_iam_role_policy_attachment" "cloudWatch-access-policy-attachment" {
58  role       = "${aws_iam_role.role_for_lambda.name}"
59  policy_arn = "arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"
60}
61
62resource "aws_lambda_function" "yanbin-test-lambda" {
63  filename         = "target/hello-1.0.jar"
64  function_name    = "yanbin-test-lambda"
65  role             = "${aws_iam_role.role_for_lambda.arn}"
66  handler          = "cc.unmi.Handler"
67  source_code_hash = "${base64sha256(file("target/hello-1.0.jar"))}"
68  runtime          = "java8"
69  timeout          = 300
70  memory_size      = 512
71  description      = "Test Lambda created by Terraform"
72
73  environment {
74    variables = {
75      BUCKET_NAME = "yanbin-test-bucket"
76    }
77  }
78}
79
80resource "aws_lambda_event_source_mapping" "kinesis_trigger" {
81  batch_size        = 3
82  event_source_arn  = "${aws_kinesis_stream.test-stream.arn}"
83  enabled           = true
84  function_name     = "${aws_lambda_function.yanbin-test-lambda.arn}"
85  starting_position = "LATEST"
86}

 

由于贴代码有些问题,所以直接截的图。main.tf 文件创建好,照例要在当前目录中运行 terraform init 先初始,而后才能执行 terraform plan|apply 等命令。编写好的 mail.tf 文件可以用 terraform fmt 帮我们格式化,在运行 terraform apply 之前最好运行一下  terraform plan, 好知道将要发生什么事。

terraform apply 执行上面的配置,Terraform 将会做以下事情
  1. 创建 Bucket yanbin-test-bucket, 访问规则是 private, 设定 Tag Environment = "test"
  2. 创建 Kinesis Stream yanbin-test-stream, Shard 数目是 2,设定 Tag Environment = "test"
  3. 创建 IAM Role yanbin-lambda_role, 并赋予 S3, Kinesis, CloudWatch 的完全访问权限
  4. 上传程序包部署 Lambda yanbin-test-lambda, 并设置 role 为上一步创建的 role, 设置其他属性,及环境变量 BUCKET. 以后运行 terraform plan 只有发现 hello-1.0.jar 包的哈稀值变了才会更新 Lambda 程序包
  5. 为上面的 Lambda 创建一个 Kinesis Trigger, batchSize 为 3, 监听第 2 步创建的 Kinesis Stream

现在一切准备就绪,可以登陆到 AWS 的控制台看下 Terraform 是不是为我们创建好了应有的东西。一切正常的就可以发送 Kinesis 消息到我们新创建的 Kinesis Stream 了,看看在 Bucket 里是不是有了 Lambda 生成的文件。

上面创建的东西不想要了,想统统干掉,那就更简单了 terraform destroy 就行了,简值是键删除。 永久链接 https://yanbin.blog/terraform-deploy-lambda-create-resources/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。