Alla fine del 2020, AWS ha annunciato il supporto delle immagini dei container per Lambda. Questa funzione ti consente di creare pacchetti e distribuire funzioni Lambda come immagini di container fino a 10 GB di dimensione. Questo articolo illustra come utilizzare Terraform per distribuire funzioni Lambda Python supportate dall'immagine del contenitore. In questo articolo, spieghiamo come utilizzare Terraform per distribuire funzioni Python Lambda supportate dall'immagine del contenitore.
Una delle attività comuni nel mondo del cloud è replicare i repository del codice sorgente da locale al cloud o tra ambienti cloud. Quindi, per illustrare l'approccio, abbiamo deciso di aggiungere il supporto Git e GitPython alla funzione Lambda.
Struttura del progetto
Ecco una struttura del progetto che utilizzeremo durante questa demo:
$ tree lambda_container
lambda_container
├── README.md
├── lambdas
│ └── git_client
│ ├── Dockerfile
│ └── index.py
└── main.tf
2 directories, 4 files
lambdas
– la cartella in cui mettiamo il codice sorgente delle funzioni Lambdamain.tf
– Codice demo Terraform, che creerà il container Docker per la funzione git_client Lambda e distribuirà la funzione in seguito
File Docker
Descriviamo un contenitore Docker che ospiterà tutte le dipendenze per le nostre funzioni lambda. Ecco il Dockerfile
contenuto:
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" ]
Prendiamo come base l'immagine Docker pubblica di Python 3.8 da Amazon. Quindi installiamo Git, puliamo le cache yum per ridurre il contenitore e installiamo le dipendenze necessarie, che ci consentono di utilizzare Git con CodeCommit utilizzando IAM per l'autenticazione.
Successivamente, stiamo copiando il index.py
file nella cartella in cui dovrebbe risiedere il codice della funzione Lambda. Consulta Utilizzo delle variabili di ambiente AWS Lambda per ulteriori informazioni.
Infine, stiamo specificando di eseguire il metodo del gestore dal file index.py all'avvio del contenitore.
Codice Lambda
Non appena la dichiarazione del contenitore Lambda è finalizzata, possiamo scrivere una funzione Lambda, che la utilizzerà. Ecco un esempio di codice, che mostrerà come clonare il repository Git. Sono sicuro che sarai in grado di adattare questo esempio alle tue esigenze personali:
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 questo codice, dichiariamo le librerie Python richieste, alcune costanti, la configurazione del logger e un paio di funzioni:
def clone(branch='master')
– questa funzione mostra come clonare il repository Gitdef handler(event, context)
– questa funzione è il punto di ingresso principale della funzione Lambda, registra l'evento in arrivo e chiamaclone
funzione
Codice Terraform
Non appena abbiamo il codice Lambda e ne dichiariamo il contenitore, possiamo scrivere del codice Terraform per automatizzare la distribuzione. Eccolo:
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
}
Questo codice Terraform è stato testato utilizzando Terraform versione 0.14.8.
In questo esempio, utilizziamo le seguenti risorse di terraform:
aws_ecr_repository
– crea un registro ECR in cui Terraform salverà l'immagine del contenitore Docker, che verrà successivamente utilizzata dalla nostra funzione Lambdanull_resource
– viene utilizzato per creare un container Docker e inviarlo al registro ECR, attiva le modifiche dei controlli nel codice della funzione Lambda e nel Dockerfile e consente a Terraform di capire quando ricostruire l'immagine e aggiornare la funzione Lambdaaws_ecr_image
– ci consente di richiedere informazioni sull'immagine Docker pubblicataaws_iam_role
,aws_iam_policy_document
eaws_iam_policy
– dichiara un'autorizzazione (invio log a CloudWatch, accesso CodeCommit) per la funzione Lambdaaws_lambda_function
– Dichiarazione della funzione Lambda stessa
Distribuzione
Per testare la soluzione devi prima distribuire il codice Terraform:
terraform init
terraform apply -auto-approve
Quindi devi eseguire la funzione Lambda:
aws lambda invoke --function-name git-lambda out --log-type Tail --query 'LogResult' --output text | base64 -d
Ecco un output previsto:
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
Pulizia
Per ripulire tutto, esegui il seguente comando:
terraform destroy
Riepilogo
Questo articolo ha creato un container Docker per la funzione AWS Lambda e distribuito l'intera soluzione utilizzando Terraform. Ci auguriamo che tu abbia trovato utile questo articolo. Se è così, per favore, aiutaci a diffonderlo nel mondo. In caso di domande, non esitare a farle nella sezione chat qui sotto.