Bu örnekte, Golang için bir AWS Lambda Terraform modülü oluşturacağız. Ayrıca bu Lambda işlevine ayrılmış bir AWS CloudWatch günlük grubu oluşturacağız.


Terraform kullanıcınız, aws_iam_policy_document için ec2.*, iam:*, lambda:*, logs.* AWS izinlerine ihtiyaç duyacaktır. Aslında her şeye izin vermek yerine tam olarak neyin gerekli olduğunu seçmelisiniz.


Yapı


blog
├── .gitignore
├── cmd
│   └── greeter
│   └── main.go
├── go.mod
├── go.sum
└── terraform
├── development
│   └── lambda.tf
└── modules
└── lambda_go
├── main.tf
└── variables.tf

.gitignore


bin/
tmp/

.terraform/
terraform.tfstate*

main.go


package main

import (
"context"
"fmt"
"os"

"github.com/aws/aws-lambda-go/lambda"
)

type Request struct {
Name string `json:"name"`
}

type Response struct {
Greeting string `json:"greeting"`
}

func HandleRequest(ctx context.Context, req Request) (Response, error) {
fmt.Printf("Request (%s - %s): %+v\n", os.Getenv("ENV"), os.Getenv("VER"), req)

return Response{Greeting: fmt.Sprintf("Hello %s!", req.Name)}, nil
}

func main() {
lambda.Start(HandleRequest)
}

lambda.tf


provider "aws" {
region = "eu-west-1"
profile = "development"
}

module "greeter_lambda" {
source = "../modules/lambda_go"

aws_region = "eu-west-1"
aws_profile = "development"

app_repository = "blog"

lambda_timeout = 5
lambda_memory_size = 128
lambda_function_name = "greeter"
lambda_environment_vars = {
ENV = "dev"
VER = "v0.0.1"
}

go_source_path = "${path.module}/../../cmd/greeter/..."
go_binary_path = "${path.module}/../../bin/greeter"
go_zip_path = "${path.module}/../../tmp/greeter.zip"

log_retention = 30
}

variables.tf


variable "aws_region" {
description = "AWS region where the resources are provisioned."
type = string
}

variable "aws_profile" {
description = "AWS profile where the application is provisioned."
type = string
}

variable "app_repository" {
description = "The application repository name."
type = string
}

variable "lambda_timeout" {
description = "Amount of time the Lambda function can run in seconds."
type = number
}

variable "lambda_memory_size" {
description = "Amount of memory the Lambda function can use at runtime in MB."
type = number
}

variable "lambda_function_name" {
description = "The name of the Lambda function."
type = string
}

variable "lambda_environment_vars" {
description = "A list of optional Lambda environment variables."
type = map(string)
}

variable "go_source_path" {
description = "The source path for the Golang code."
type = string
}

variable "go_binary_path" {
description = "The binary path for the Golang code."
type = string
}

variable "go_zip_path" {
description = "The zip path for the Lambda function."
type = string
}

variable "log_retention" {
description = "The number of days to retain log events in the log group."
type = number
}

main.go


terraform {
required_version = "~> 1.4.4"

required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.30.0"
}

archive = {
source = "hashicorp/archive"
version = "~> 2.3.0"
}

null = {
source = "hashicorp/null"
version = "~> 3.2.1"
}
}
}

# LOCALS -----------------------------------------------------------------------

locals {
lambda_environment_vars = var.lambda_environment_vars[*]
}

# FUNCTION ---------------------------------------------------------------------

resource "null_resource" "go_binary_file" {
provisioner "local-exec" {
command = "GOOS=linux GOARCH=amd64 CGO_ENABLED=0 GOFLAGS=-trimpath go build -mod=readonly -ldflags='-s -w' -o ${var.go_binary_path} ${var.go_source_path}"
}
}

data "archive_file" "go_zip_file" {
type = "zip"
source_file = var.go_binary_path
output_path = var.go_zip_path

depends_on = [
null_resource.go_binary_file,
]
}

resource "aws_lambda_function" "go" {
function_name = "${var.app_repository}-${var.lambda_function_name}"
handler = var.lambda_function_name
filename = var.go_zip_path
package_type = "Zip"
runtime = "go1.x"
timeout = var.lambda_timeout
memory_size = var.lambda_memory_size

role = aws_iam_role.lambda_execution.arn
source_code_hash = data.archive_file.go_zip_file.output_base64sha256

dynamic "environment" {
for_each = local.lambda_environment_vars
content {
variables = environment.value
}
}

depends_on = [
aws_iam_role_policy_attachment.lambda_logs,
aws_cloudwatch_log_group.lambda_log_group,
]
}

# POLICY DOCUMENTS -------------------------------------------------------------

data "aws_iam_policy_document" "lambda_execution" {
version = "2012-10-17"
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["lambda.amazonaws.com"]
}
}
}

data "aws_iam_policy_document" "lambda_logging" {
version = "2012-10-17"
statement {
effect = "Allow"
actions = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
]
resources = ["arn:aws:logs:*:*:*"]
}
}

# ROLE -------------------------------------------------------------------------

resource "aws_iam_role" "lambda_execution" {
name = "lambda-execution"
description = "Assume execution role when invoked."

assume_role_policy = data.aws_iam_policy_document.lambda_execution.json
}

# LOGGING ----------------------------------------------------------------------

resource "aws_iam_policy" "lambda_logging" {
name = "lambda-logging"
description = "Grant logging role permissions."

policy = data.aws_iam_policy_document.lambda_logging.json
}

resource "aws_iam_role_policy_attachment" "lambda_logs" {
role = aws_iam_role.lambda_execution.name
policy_arn = aws_iam_policy.lambda_logging.arn
}

resource "aws_cloudwatch_log_group" "lambda_log_group" {
name = "/aws/lambda/${var.app_repository}-${var.lambda_function_name}"
retention_in_days = var.log_retention
}

AWS CLI yapılandırma


[default]
region = eu-west-1
output = json

[profile development]
source_profile = default
role_session_name = github-actions
role_arn = arn:aws:iam::1234567890:role/provisioner

[default]
aws_access_key_id = QWERTYU12345678
aws_secret_access_key = QWERTY123456qwertyu09876

Kurulum


blog/terraform/development$ terraform apply

Sonuç