Fin 2020, AWS a annoncé la prise en charge des images de conteneurs pour Lambda. Cette fonctionnalité vous permet de regrouper et de déployer des fonctions Lambda en tant qu'images de conteneur d'une taille maximale de 10 Go. Cet article explique comment vous pouvez utiliser Terraform pour déployer des fonctions Python Lambda basées sur l'image du conteneur. Dans cet article, nous expliquons comment vous pouvez utiliser Terraform pour déployer des fonctions Python Lambda basées sur l'image du conteneur.
L'une des tâches courantes dans le monde du cloud consiste à répliquer les référentiels de code source sur site vers le cloud ou entre les environnements cloud. Ainsi, pour illustrer l'approche, nous avons décidé d'ajouter la prise en charge de Git et GitPython à la fonction Lambda.
Structure du projet
Voici une structure de projet que nous utiliserons au cours de cette démo :
$ tree lambda_container
lambda_container
├── README.md
├── lambdas
│ └── git_client
│ ├── Dockerfile
│ └── index.py
└── main.tf
2 directories, 4 files
lambdas
– le dossier où nous mettons le code source des fonctions Lambdamain.tf
– Code de démonstration Terraform, qui construira le conteneur Docker pour la fonction Lambda git_client et déploiera la fonction par la suite
Fichier Docker
Décrivons un conteneur Docker qui hébergera toutes les dépendances de nos fonctions lambda. Voici le Dockerfile
contenu :
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" ]
Nous prenons l'image Docker publique Python 3.8 d'Amazon comme base. Ensuite, nous installons Git, nettoyons les caches yum pour réduire la taille du conteneur et installons les dépendances requises, ce qui nous permet d'utiliser Git avec CodeCommit en utilisant IAM pour l'authentification.
Ensuite, nous copions le index.py
fichier dans le dossier où le code de la fonction Lambda doit résider. Consultez Utilisation des variables d'environnement AWS Lambda pour plus d'informations.
Enfin, nous spécifions d'exécuter la méthode du gestionnaire à partir du fichier index.py au lancement du conteneur.
Code lambda
Dès que la déclaration du conteneur Lambda est finalisée, nous pouvons écrire une fonction Lambda, qui l'utilisera. Voici un exemple de code, qui montrera comment cloner le référentiel Git. Je suis sûr que vous pourrez adapter cet exemple à vos besoins personnels :
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()
Dans ce code, nous déclarons les bibliothèques Python requises, certaines constantes, la configuration de l'enregistreur et quelques fonctions :
def clone(branch='master')
– cette fonction montre comment cloner le dépôt Gitdef handler(event, context)
– cette fonction est le point d'entrée principal de la fonction Lambda, elle enregistre l'événement entrant et appelleclone
fonction
Code Terraform
Dès que nous avons du code Lambda et que nous déclarons son conteneur, nous pouvons écrire du code Terraform pour automatiser le déploiement. Le voici :
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
}
Ce code Terraform a été testé avec Terraform version 0.14.8.
Dans cet exemple, nous utilisons les ressources terraform suivantes :
aws_ecr_repository
– crée un registre ECR où Terraform enregistrera l'image du conteneur Docker, qui sera ensuite utilisée par notre fonction Lambdanull_resource
- est utilisé pour créer un conteneur Docker et le pousser vers le registre ECR, déclenche des vérifications des modifications dans le code de la fonction Lambda et Dockerfile et permet à Terraform de comprendre quand reconstruire l'image et mettre à jour la fonction Lambdaaws_ecr_image
– nous permet de demander des informations sur l'image Docker publiéeaws_iam_role
,aws_iam_policy_document
etaws_iam_policy
– déclare une autorisation (envoyer des journaux à CloudWatch, accéder à CodeCommit) pour la fonction Lambdaaws_lambda_function
– Déclaration de la fonction Lambda elle-même
Déploiement
Pour tester la solution, vous devez d'abord déployer le code Terraform :
terraform init
terraform apply -auto-approve
Ensuite, vous devez exécuter la fonction Lambda :
aws lambda invoke --function-name git-lambda out --log-type Tail --query 'LogResult' --output text | base64 -d
Voici une sortie attendue :
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
Nettoyage
Pour tout nettoyer, exécutez la commande suivante :
terraform destroy
Résumé
Cet article a créé un conteneur Docker pour la fonction AWS Lambda et déployé l'intégralité de la solution à l'aide de Terraform. Nous espérons que vous avez trouvé cet article utile. Si oui, s'il vous plaît, aidez-nous à le diffuser dans le monde. Si vous avez des questions, n'hésitez pas à les poser dans la section de chat ci-dessous.