Bei FloqAST verwenden wir AWS Lambda Functions hinter einem Application Load Balancer als unsere primäre API-Plattform. Jede unserer Lambda-Funktionen befindet sich in einem separaten Git-Repository, und die unterstützende Terraform befindet sich zusammen mit dem Lambda-Quellcode im Repo. Das ist großartig, weil es Ingenieuren die vollständige Kontrolle über ihren Teil der Anwendung gibt. Die Verteilung des Quellcodes auf mehrere Repos löst einige Probleme, erhöht aber auch die Komplexität. Wir können die Lambda-Funktion nicht einfach an die ALB anhängen, indem wir direkt auf die Ressource verweisen, da wir die ALB-Ressource nicht in unserem lokalen Repository haben. Hier ist ein Beispiel dafür, wie ein ALB-System aussehen könnte.

ALB-Datenquellen
Hier setzen wir Terraform ein Datenquellen um das Remote-ALB nachzuschlagen, an das wir unsere Lambda-Funktion anhängen werden. Wir müssen hier tatsächlich zwei Datenquellen-Suchen durchführen. Zuerst brauchen wir die ALB, damit wir das nutzen können Ressourcen-ARN um das nachzuschlagen Zuhörer. Der Listener ist das, woran wir eigentlich unsere Zielgruppe und die Lambda-Funktion anhängen.
data aws_lb alb {
name = var.alb_name
}
data aws_lb_listener alb443 {
load_balancer_arn = data.aws_lb.alb.arn
port = 443
}
Ressourcen zur Lambda-Funktion
Jetzt, da wir den Application Load Balancer haben, müssen wir unsere Ressourcen für die Lambda-Funktion erstellen.
- Lambda-Funktion
- Lambda-Alias Wir schaffen eine
live
Alias für alle unsere Lambda-Funktionen. (fakultativ) - Zielgruppe
- Lambda-Genehmigung um der Zielgruppe zu ermöglichen, die Lambda-Funktion aufzurufen.
- Zielgruppenanbindung um die Zielgruppe an die Lambda-Funktion zu binden.
resource aws_lambda_function main {
function_name = var.lambda_name
...
}
resource aws_lambda_alias live {
name = "live"
description = "Live alias"
function_name = aws_lambda_function.main.arn
function_version = aws_lambda_function.main.version
}
resource aws_lb_target_group main {
name = "${substr(var.lambda_name, 0, 29)}-tg"
target_type = "lambda"
...
}
resource aws_lambda_permission alb {
statement_id = "AllowExecutionFromALB"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.main.function_name
principal = "elasticloadbalancing.amazonaws.com"
qualifier = aws_lambda_alias.live.name
source_arn = aws_lb_target_group.main.arn
}
resource aws_lb_target_group_attachment main {
target_group_arn = aws_lb_target_group.main.arn
target_id = aws_lambda_alias.live.arn
depends_on = [ aws_lambda_permission.alb ]
}
Das Unterstr wird verwendet, um den Namen der Zielgruppe aufgrund der Beschränkung auf 32 Zeichen abzukürzen.
Verbindung herstellen
Wir haben unsere ALB-Datenquellen und wir haben unsere Lambda-Funktion, Zielgruppe und andere Konfigurationen. Als nächstes müssen wir alles miteinander verbinden. Wir werden dies mit zwei letzten Ressourcen tun.
- Zielgruppenanbindung verbindet die Zielgruppe mit der Lambda-Funktion.
- ALB-Listener-Regel verbindet das ALB mit der Zielgruppe.
resource aws_lb_target_group_attachment main {
target_group_arn = aws_lb_target_group.main.arn
target_id = aws_lambda_alias.live.arn
depends_on = [
aws_lambda_permission.alb,
aws_lambda_alias.live
]
}
resource aws_lb_listener_rule main {
listener_arn = data.aws_lb_listener.alb443.arn
action {
type = "forward"
target_group_arn = aws_lb_target_group.main.arn
}
condition {
path_pattern {
values = local.alb_path
}
}
condition {
http_request_method {
values = var.alb_request_methods
}
}
}
Beachten Sie unsere Verwendung von local.alb_path, dies wird im nächsten Abschnitt behandelt.
Eingaben
Wir versuchen so viel wie möglich zu abstrahieren, sodass der Ingenieur, der die Lambda-Funktion entwickelt, so wenige Werte wie möglich eingeben muss. Hier sind die Eingabevariablen, die erforderlich sind, damit dieses Beispiel funktioniert, aber intern verwenden wir unsere Deployment-Pipeline und Lokale Werte von Terraform um noch weiter zu abstrahieren.
variable lambda_name {
description = "A unique name for your Lambda Function."
type = string
}
variable alb_name {
description = "The name of the Application Load Balancer."
type = string
}
variable alb_path {
description = "The path to be created on the ALB."
type = string
default = null
}
variable alb_request_methods {
description = "The request methods to be created on the ALB."
type = list(string)
default = ["OPTIONS", "GET"]
}
locals {
alb_path = var.alb_path != null ? var.alb_path ? var.lambda_name
}
Beachten Sie, dass wir eine verwenden lokal um den Alb_Path standardmäßig auf den Namen der Lambda-Funktion einzustellen. Dies reduziert die erforderlichen Eingaben.
Ein neues Problem — Module sind die Rettung!
Wir haben das ursprüngliche Problem gelöst, eine neue Lambda-Funktion an eine bestehende ALB anzuhängen, auf die wir über Terraform keinen direkten Ressourcenzugriff haben, indem wir Datenquellen.Jetzt haben wir ein neues Problem der Terraform-Codeduplizierung in vielen Anwendungsrepositorys. Wir haben dieses Problem bei FloqAst gelöst, indem wir den obigen Terraform-Code in einen umgewandelt haben Terraform-ModulDurch die Verwendung eines Moduls können wir den gleichen Terraform-Code für alle unsere Lambda-Funktionen in einem einzigen Repository verwalten. Der einzige Terraform-Code, der sich jetzt im Anwendungs-Repository befindet, ist ein einzelner modul.tf
Datei, die ungefähr so aussieht.
provider aws {
region = "us-west-2"
}
module lambda-platform {
source = "git@github.com:FloQast/terraform-module-lambda-platform.git?ref=v1.4.0"
lambda_name = "sample-lambda"
alb_path = ["/my-sample-path"]
}
In unserem Terraform-Modul „Lambda Platform“ stellen wir eine ganze Reihe von Anpassungsoptionen zur Verfügung, aber nur wenige Eingaben sind tatsächlich erforderlich. Auf diese Weise können unsere Techniker schnell neue API-Endpunkte einrichten, ohne viel Zeit damit verbringen zu müssen, über die zugrunde liegende Infrastruktur nachzudenken, und gleichzeitig haben sie die Möglichkeit, so viele Anpassungen vorzunehmen, wie sie benötigen.