Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/lambda #9

Merged
merged 32 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b5f7f83
feat: adiciona arquivos terraform
nathansouzaa3 Oct 8, 2024
8c133c7
feat: adiciona codigo da lambda
nathansouzaa3 Oct 8, 2024
4ace87b
feat: adiciona pipeline de deploy
nathansouzaa3 Oct 8, 2024
4c3817b
Merge remote-tracking branch 'origin/main' into feature/lambda
nathansouzaa3 Oct 8, 2024
f1ee305
fix: remove profile
nathansouzaa3 Oct 8, 2024
6913580
feat: ajusta organização das pastas
nathansouzaa3 Oct 8, 2024
9bf16c7
fix: ajusta pipeline
nathansouzaa3 Oct 8, 2024
5d9f512
feat: adiciona push imagem docker
nathansouzaa3 Oct 8, 2024
8e1742c
feat: adiciona create_infra da lambda
nathansouzaa3 Oct 8, 2024
9bf9536
fix: ajusta terraform para buscar ecr existente
nathansouzaa3 Oct 8, 2024
96b2f6b
feat: adiciona o create infra no pipeline
nathansouzaa3 Oct 8, 2024
145395f
fix: arruma nome do script
nathansouzaa3 Oct 8, 2024
e6e6160
fix: ajusta poetry no dockerfile
nathansouzaa3 Oct 8, 2024
eb21bec
fix: ajusta terraform
nathansouzaa3 Oct 8, 2024
aaa990f
feat: adicione bucket s3
nathansouzaa3 Oct 8, 2024
15f599a
fix: remove config duplicada
nathansouzaa3 Oct 8, 2024
9db68f5
fix: remove variavel do nome do bucket
nathansouzaa3 Oct 8, 2024
aee22ac
fix: ajusta criação da iam role
nathansouzaa3 Oct 8, 2024
2fff4b2
fix: ajusta comando do terraform
nathansouzaa3 Oct 8, 2024
6373e3f
feat: adiciona diretorio dockerfile
nathansouzaa3 Oct 8, 2024
4463ae3
fix: cria arquivo push_image lambda
nathansouzaa3 Oct 8, 2024
55aba98
fix: ajusta dockerfile
nathansouzaa3 Oct 8, 2024
62b6e30
feat: adiciona modelo para teste
nathansouzaa3 Oct 8, 2024
a82d441
feat: adiciona pipeline de destroy
nathansouzaa3 Oct 8, 2024
f3a999f
fix: ajusta pipeline para rodar manualmente
nathansouzaa3 Oct 8, 2024
103991d
teste pipeline destroy
nathansouzaa3 Oct 8, 2024
fc274dc
fix: ajusta pipeline para rodar manualmente
nathansouzaa3 Oct 8, 2024
41b3b0f
fix: ajusta organização das pastas
nathansouzaa3 Oct 8, 2024
d331629
fix: ajusta nome da branch
nathansouzaa3 Oct 8, 2024
be6635a
remove modelo do repo
nathansouzaa3 Oct 8, 2024
0f1bbdf
remove arquivo tfstate
nathansouzaa3 Oct 9, 2024
4336c59
fix: ajusta nome do repo
nathansouzaa3 Oct 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
nathansouzaa3 marked this conversation as resolved.
Show resolved Hide resolved
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"