Skip to content

Commit

Permalink
Merge pull request #9 from A3Data/feature/lambda
Browse files Browse the repository at this point in the history
Feature/lambda
  • Loading branch information
henrique-tostes-a3 authored Oct 9, 2024
2 parents 6911108 + 4336c59 commit f4a4e92
Show file tree
Hide file tree
Showing 13 changed files with 312 additions and 0 deletions.
52 changes: 52 additions & 0 deletions .github/workflows/pipeline_deploy_lambda.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Pipeline de Deploy Lambda

on:
push:
branches:
- main

permissions:
id-token: write
contents: read

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- name: Check out code
uses: actions/checkout@v4
with:
ref: ${{ github.ref }}

- name: Set up Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.8.0

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: "arn:aws:iam::340752815603:role/oidc-github-framework-eml-role"
role-session-name: GitHub_to_AWS_via_FederatedOIDC
aws-region: ${{ env.AWS_REGION }}

- name: Create ECR
run: |
chmod +x deployment/scripts/create_ecr.sh
./deployment/scripts/create_ecr.sh ${{ env.REPO_NAME }} ${{ env.AWS_REGION }}
- name: Build and push image
run: |
chmod +x deployment/scripts/push_image_lambda.sh
./deployment/scripts/push_image_lambda.sh ${{ env.REPO_NAME }} ${{ env.AWS_REGION }}
- name: Create infra and deploy
run: |
chmod +x deployment/scripts/create_infra_lambda.sh
./deployment/scripts/create_infra_lambda.sh ${{ env.AWS_REGION }}
env:
REPO_NAME: "eml-online-repo"
AWS_REGION: "us-east-1"
39 changes: 39 additions & 0 deletions .github/workflows/pipeline_destroy_lambda.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Pipeline de Destroy Lambda

on:
workflow_dispatch:

permissions:
id-token: write
contents: read

jobs:
destroy:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.ref }}

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: "arn:aws:iam::340752815603:role/oidc-github-framework-eml-role"
role-session-name: GitHub_to_AWS_via_FederatedOIDC
aws-region: ${{ env.AWS_REGION }}

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.8.0

- name: Destroy infrastructure
run: |
chmod +x deployment/scripts/destroy_infra_lambda.sh
./deployment/scripts/destroy_infra_lambda.sh ${{ env.AWS_REGION }}
env:
REPO_NAME: "eml-online-repo"
AWS_REGION: "us-east-1"
48 changes: 48 additions & 0 deletions api/lambda/app/lambda_function.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import json
import pandas as pd
from src.pipelines.predict import load_model, make_predictions


MODEL_FILE = "artifacts/models/model.joblib"
model = load_model(MODEL_FILE)


def validate_input(item):
"""Valida se o item contém pelo menos um valor e é uma lista com o tamanho correto."""
if not item or not isinstance(item, list) or len(item) != 4:
raise ValueError("O item deve ser uma lista com 4 valores.")


def make_prediction(item):
"""Faz previsão com base nos dados de entrada."""
data = pd.DataFrame(
[item], columns=["sepal_length", "sepal_width", "petal_length", "petal_width"]
)
prediction = make_predictions(model, data)
return prediction.astype(int).tolist()[0]


def process_event(event):
"""Processa o evento e gera previsões."""
if isinstance(event, str):
event = json.loads(event)
if "body" in event:
body = json.loads(event["body"])
else:
body = event
predictions = []

for item in body:
try:
validate_input(item)
prediction = make_prediction(item)
predictions.append({"prediction": prediction})
except Exception as e:
predictions.append({"error": str(e)})
return predictions


def lambda_handler(event, context):
"""Função principal que recebe o evento e contexto."""
predictions = process_event(event)
return {"statusCode": 200, "body": json.dumps(predictions)}
22 changes: 22 additions & 0 deletions deployment/docker/Dockerfile.lambda
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM public.ecr.aws/lambda/python:3.10

# Instalar o Poetry
RUN pip install poetry

# Copiar arquivos de configuração do Poetry
COPY pyproject.toml poetry.lock* ./

# Configurar o Poetry para não criar virtualenv
RUN poetry config virtualenvs.create false

# Instalar as dependências do projeto
RUN poetry install --no-dev

# Copiar os artefatos e o código-fonte
COPY artifacts/ artifacts/
COPY api/lambda/app/lambda_function.py ./
COPY src/ src/
COPY config/ config/

# Comando padrão para executar a função Lambda
CMD ["lambda_function.lambda_handler"]
32 changes: 32 additions & 0 deletions deployment/infrastructure/terraform-lambda/api_gateway.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
resource "aws_api_gateway_rest_api" "api" {
name = "PredictionAPI"
description = "API para a função Lambda de previsão"
}

resource "aws_api_gateway_resource" "predict" {
rest_api_id = aws_api_gateway_rest_api.api.id
parent_id = aws_api_gateway_rest_api.api.root_resource_id
path_part = "predict"
}

resource "aws_api_gateway_method" "predict_method" {
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.predict.id
http_method = "POST"
authorization = "NONE"
}

resource "aws_api_gateway_integration" "predict_integration" {
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.predict.id
http_method = aws_api_gateway_method.predict_method.http_method
integration_http_method = "POST"
type = "AWS_PROXY"
uri = "arn:aws:apigateway:${var.region}:lambda:path/2015-03-31/functions/${aws_lambda_function.prediction_eml_lambda.arn}/invocations"
}

resource "aws_api_gateway_deployment" "api_deployment" {
depends_on = [aws_api_gateway_integration.predict_integration]
rest_api_id = aws_api_gateway_rest_api.api.id
stage_name = "prod"
}
23 changes: 23 additions & 0 deletions deployment/infrastructure/terraform-lambda/iam.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
resource "aws_iam_role" "prediction_eml_role" {
name = "prediction_eml_role"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Principal = {
Service = "lambda.amazonaws.com"
}
Effect = "Allow"
Sid = ""
},
]
})
}

resource "aws_iam_policy_attachment" "prediction_eml_policy_attachment" {
name = "prediction_eml_policy_attachment"
roles = [aws_iam_role.prediction_eml_role.name]
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
26 changes: 26 additions & 0 deletions deployment/infrastructure/terraform-lambda/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
terraform {
backend "s3" {
bucket = var.bucket_name
key = "terraform/terraform.tfstate"
region = "us-east-1"
encrypt = true
}
}

resource "aws_lambda_function" "prediction_eml_lambda" {
function_name = "prediction_eml"
role = aws_iam_role.prediction_eml_role.arn
package_type = "Image"
image_uri = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/${var.repository_name}:latest"

memory_size = 256
timeout = 120
}

resource "aws_lambda_permission" "allow_api_gateway" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.prediction_eml_lambda.function_name
principal = "apigateway.amazonaws.com"
source_arn = "${aws_api_gateway_rest_api.api.execution_arn}/*/*"
}
4 changes: 4 additions & 0 deletions deployment/infrastructure/terraform-lambda/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "api_url" {
value = "https://${aws_api_gateway_rest_api.api.id}.execute-api.${var.region}.amazonaws.com/prod/predict"
description = "URL do endpoint da API"
}
5 changes: 5 additions & 0 deletions deployment/infrastructure/terraform-lambda/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
provider "aws" {
region = var.region
}

data "aws_caller_identity" "current" {}
10 changes: 10 additions & 0 deletions deployment/infrastructure/terraform-lambda/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
variable "repository_name" {
description = "Nome do repositório ECR"
type = string
default = "prediction-eml"
}

variable "region" {
description = "A região onde a infraestrutura será criada."
default = "us-east-1"
}
18 changes: 18 additions & 0 deletions deployment/scripts/create_infra_lambda.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash
set -e

ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
BUCKET_NAME="$ACCOUNT_ID-prediction-eml"
AWS_REGION=$1

# Verifica se o bucket existe
if aws s3api head-bucket --bucket "$BUCKET_NAME" 2>/dev/null; then
echo "O bucket '$BUCKET_NAME' já existe."
else
# Se o bucket não existir, cria o bucket
aws s3api create-bucket --bucket "$BUCKET_NAME" --region us-east-1
echo "Bucket '$BUCKET_NAME' criado com sucesso."
fi

terraform -chdir="deployment/infrastructure/terraform-lambda" init -backend-config="bucket=$BUCKET_NAME" -backend-config="region=$AWS_REGION"
terraform -chdir="deployment/infrastructure/terraform-lambda" apply -auto-approve
21 changes: 21 additions & 0 deletions deployment/scripts/destroy_infra_lambda.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash
set -e

ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
BUCKET_NAME="$ACCOUNT_ID-prediction-eml"
AWS_REGION=$1

# Verifica se o bucket existe
if aws s3api head-bucket --bucket "$BUCKET_NAME" 2>/dev/null; then
echo "O bucket '$BUCKET_NAME' já existe."
else
# Se o bucket não existir, cria o bucket
aws s3api create-bucket --bucket "$BUCKET_NAME" --region us-east-1
echo "Bucket '$BUCKET_NAME' criado com sucesso."
fi

# Inicializa o Terraform
terraform -chdir="deployment/infrastructure/terraform-lambda" init -backend-config="bucket=$BUCKET_NAME" -backend-config="region=$AWS_REGION"

# Comando para destruir a infraestrutura
terraform -chdir="deployment/infrastructure/terraform-lambda" destroy -auto-approve
12 changes: 12 additions & 0 deletions deployment/scripts/push_image_lambda.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
set -e

DOCKER_IMAGE_NAME=$1
AWS_REGION=$2
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REPO_URI="$ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$DOCKER_IMAGE_NAME"

docker build -t $DOCKER_IMAGE_NAME -f deployment/docker/Dockerfile.lambda .
docker tag "$DOCKER_IMAGE_NAME:latest" "$REPO_URI:latest"
aws ecr get-login-password --region "$AWS_REGION" | docker login --username AWS --password-stdin "$REPO_URI"
docker push "$REPO_URI:latest"

0 comments on commit f4a4e92

Please sign in to comment.