Ende 2020 kündigte AWS die Unterstützung von Container-Images für Lambda an. Mit dieser Funktion können Sie Lambda-Funktionen als Container-Images mit einer Größe von bis zu 10 GB verpacken und bereitstellen. In diesem Artikel wird beschrieben, wie Sie mit Terraform Python-Lambda-Funktionen bereitstellen können, die durch das Container-Image unterstützt werden. In diesem Artikel behandeln wir, wie Sie Terraform verwenden können, um Python-Lambda-Funktionen bereitzustellen, die durch das Container-Image unterstützt werden.
Eine der häufigsten Aufgaben in der Cloud-Welt ist das Replizieren von Quellcode-Repositories von On-Premises in die Cloud oder zwischen Cloud-Umgebungen. Um den Ansatz zu veranschaulichen, haben wir uns entschieden, der Lambda-Funktion Git- und GitPython-Unterstützung hinzuzufügen.
Projektstruktur
Hier ist eine Projektstruktur, die wir während dieser Demo verwenden werden:
$ tree lambda_container
lambda_container
├── README.md
├── lambdas
│ └── git_client
│ ├── Dockerfile
│ └── index.py
└── main.tf
2 directories, 4 files
lambdas
– der Ordner, in dem wir den Quellcode der Lambda-Funktionen abgelegt habenmain.tf
– Terraform-Democode, der den Docker-Container für die git_client-Lambda-Funktion erstellt und die Funktion anschließend bereitstellt
Dockerfile
Lassen Sie uns einen Docker-Container beschreiben, der alle Abhängigkeiten für unsere Lambda-Funktionen hostet. Hier ist das Dockerfile
Inhalt:
FROM public.ecr.aws/lambda/python:3.8
RUN yum update -y && \
yum install -y git && \
rm -Rf /var/cache/yum && \
pip install git-remote-codecommit boto3 GitPython awscli
COPY index.py ${LAMBDA_TASK_ROOT}
CMD [ "index.handler" ]
Wir nehmen das öffentliche Docker-Image von Python 3.8 von Amazon als Basis. Dann installieren wir Git, bereinigen die yum-Caches, um den Container kleiner zu machen, und installieren die erforderlichen Abhängigkeiten, die es uns ermöglichen, Git mit CodeCommit unter Verwendung von IAM zur Authentifizierung zu verwenden.
Als nächstes kopieren wir die index.py
Datei in den Ordner, in dem sich der Lambda-Funktionscode befinden sollte. Weitere Informationen finden Sie unter Verwenden von AWS Lambda-Umgebungsvariablen.
Schließlich geben wir an, dass die Handler-Methode aus der Datei index.py beim Containerstart ausgeführt werden soll.
Lambda-Code
Sobald die Deklaration des Lambda-Containers abgeschlossen ist, können wir eine Lambda-Funktion schreiben, die sie verwendet. Hier ist ein Codebeispiel, das zeigt, wie man ein Git-Repository klont. Ich bin sicher, Sie können dieses Beispiel an Ihre persönlichen Bedürfnisse anpassen:
import logging
import os
import git
TMP_DIR = "/tmp"
REPO_DIR = 'aws-config-rules'
REPO_URL = f'https://github.com/andreivmaksimov/{REPO_DIR}'
CLONE_PATH = os.path.join(TMP_DIR, REPO_DIR)
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.INFO)
def clone(branch='master'):
repo = git.Repo.clone_from(REPO_URL, CLONE_PATH, branch=branch)
with repo.config_writer() as git_config:
git_config.set_value('user', 'email', '[email protected]')
git_config.set_value('user', 'name', 'Git Lambda')
def handler(event, context):
LOGGER.info('Event: %s', event)
LOGGER.info('Cloning repo: %s', REPO_URL)
clone()
In diesem Code deklarieren wir erforderliche Python-Bibliotheken, einige Konstanten, den Logger und einige Funktionen:
def clone(branch='master')
– diese Funktion zeigt, wie man ein Git-Repository klontdef handler(event, context)
– Diese Funktion ist der Haupteinstiegspunkt zur Lambda-Funktion, sie protokolliert das eingehende Ereignis und ruftclone
auf Funktion
Terraform-Code
Sobald wir Lambda-Code haben und seinen Container deklarieren, können wir etwas Terraform-Code schreiben, um die Bereitstellung zu automatisieren. Hier ist es:
variable region {
default = "us-east-1"
}
provider aws {
region = var.region
}
data aws_caller_identity current {}
locals {
prefix = "git"
account_id = data.aws_caller_identity.current.account_id
ecr_repository_name = "${local.prefix}-demo-lambda-container"
ecr_image_tag = "latest"
}
resource aws_ecr_repository repo {
name = local.ecr_repository_name
}
resource null_resource ecr_image {
triggers = {
python_file = md5(file("${path.module}/lambdas/git_client/index.py"))
docker_file = md5(file("${path.module}/lambdas/git_client/Dockerfile"))
}
provisioner "local-exec" {
command = <<EOF
aws ecr get-login-password --region ${var.region} | docker login --username AWS --password-stdin ${local.account_id}.dkr.ecr.${var.region}.amazonaws.com
cd ${path.module}/lambdas/git_client
docker build -t ${aws_ecr_repository.repo.repository_url}:${local.ecr_image_tag} .
docker push ${aws_ecr_repository.repo.repository_url}:${local.ecr_image_tag}
EOF
}
}
data aws_ecr_image lambda_image {
depends_on = [
null_resource.ecr_image
]
repository_name = local.ecr_repository_name
image_tag = local.ecr_image_tag
}
resource aws_iam_role lambda {
name = "${local.prefix}-lambda-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow"
}
]
}
EOF
}
data aws_iam_policy_document lambda {
statement {
actions = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
effect = "Allow"
resources = [ "*" ]
sid = "CreateCloudWatchLogs"
}
statement {
actions = [
"codecommit:GitPull",
"codecommit:GitPush",
"codecommit:GitBranch",
"codecommit:ListBranches",
"codecommit:CreateCommit",
"codecommit:GetCommit",
"codecommit:GetCommitHistory",
"codecommit:GetDifferences",
"codecommit:GetReferences",
"codecommit:BatchGetCommits",
"codecommit:GetTree",
"codecommit:GetObjectIdentifier",
"codecommit:GetMergeCommit"
]
effect = "Allow"
resources = [ "*" ]
sid = "CodeCommit"
}
}
resource aws_iam_policy lambda {
name = "${local.prefix}-lambda-policy"
path = "/"
policy = data.aws_iam_policy_document.lambda.json
}
resource aws_lambda_function git {
depends_on = [
null_resource.ecr_image
]
function_name = "${local.prefix}-lambda"
role = aws_iam_role.lambda.arn
timeout = 300
image_uri = "${aws_ecr_repository.repo.repository_url}@${data.aws_ecr_image.lambda_image.id}"
package_type = "Image"
}
output "lambda_name" {
value = aws_lambda_function.git.id
}
Dieser Terraform-Code wurde mit Terraform Version 0.14.8 getestet.
In diesem Beispiel verwenden wir die folgenden Terraform-Ressourcen:
aws_ecr_repository
– Erstellt eine ECR-Registrierung, in der Terraform das Docker-Container-Image speichert, das später von unserer Lambda-Funktion verwendet wirdnull_resource
– wird verwendet, um Docker-Container zu erstellen und in die ECR-Registrierung zu übertragen, löst Prüfungen von Änderungen im Lambda-Funktionscode und in der Docker-Datei aus und ermöglicht es Terraform zu verstehen, wann das Image neu erstellt und die Lambda-Funktion aktualisiert werden mussaws_ecr_image
– ermöglicht es uns, Informationen über veröffentlichte Docker-Images abzufragenaws_iam_role
,aws_iam_policy_document
undaws_iam_policy
– deklariert eine Berechtigung (Protokolle an CloudWatch senden, CodeCommit-Zugriff) für die Lambda-Funktionaws_lambda_function
– Deklaration der Lambda-Funktion selbst
Bereitstellung
Um die Lösung zu testen, müssen Sie zuerst Terraform-Code bereitstellen:
terraform init
terraform apply -auto-approve
Dann müssen Sie die Lambda-Funktion ausführen:
aws lambda invoke --function-name git-lambda out --log-type Tail --query 'LogResult' --output text | base64 -d
Hier ist eine erwartete Ausgabe:
START RequestId: b8b742d6-5bd6-4098-90e3-5e30f5c6e816 Version: $LATEST
[INFO] 2021-03-16T02:10:28.064Z b8b742d6-5bd6-4098-90e3-5e30f5c6e816 Event: {}
[INFO] 2021-03-16T02:10:28.064Z b8b742d6-5bd6-4098-90e3-5e30f5c6e816 Cloning repo: https://github.com/andreivmaksimov/aws-config-rules
END RequestId: b8b742d6-5bd6-4098-90e3-5e30f5c6e816
REPORT RequestId: b8b742d6-5bd6-4098-90e3-5e30f5c6e816 Duration: 4069.15 ms Billed Duration: 6131 ms Memory Size: 128 MB Max Memory Used: 83 MB Init Duration: 2061.73 ms
Aufräumen
Um alles zu bereinigen, führen Sie den folgenden Befehl aus:
terraform destroy
Zusammenfassung
Dieser Artikel hat einen Docker-Container für die AWS Lambda-Funktion erstellt und die gesamte Lösung mit Terraform bereitgestellt. Wir hoffen, Sie fanden diesen Artikel hilfreich. Wenn ja, helfen Sie uns bitte, es in der Welt zu verbreiten. Wenn Sie Fragen haben, können Sie diese gerne im Chat-Bereich unten stellen.