Skip to content
Voltar

Construindo Sistema Multiagente Event-Driven para Diagnóstico de Incidentes na AWS

Atualizado:

project architectures

Arquitetura do Projeto

Aqui está o material de apoio com os códigos e demostrações de como concluir o minicurso de Python para DevOps na AWS

Table of contents

Open Table of contents

Pré-requisitos


CloudWatch Logs

aws logs create-log-group \
  --log-group-name /minicurso/cloud-incident

Importante: Todos os Log Streams serão criados dentro deste único Log Group, facilitando a configuração do Metric Filter.


Criação do Metric Filter

aws logs put-metric-filter \
  --log-group-name /minicurso/cloud-incident \
  --filter-name "ErrorDetection" \
  --filter-pattern "ERROR" \
  --metric-transformations "metricName=ErrorCount,metricNamespace=MinicursoIncidents,metricValue=1,defaultValue=0"

Criação do Alarme

aws cloudwatch put-metric-alarm \
  --alarm-name "IncidentDetected" \
  --alarm-description "Dispara quando ERROR é detectado nos logs" \
  --metric-name ErrorCount \
  --namespace MinicursoIncidents \
  --statistic Sum \
  --period 60 \
  --evaluation-periods 1 \
  --threshold 1 \
  --comparison-operator GreaterThanOrEqualToThreshold

Criação do EventBridge Rule

aws events put-rule \
  --name "DispararStepFunctionDeIncidentes" \
  --event-pattern '{
    "source": ["aws.cloudwatch"],
    "detail-type": ["CloudWatch Alarm State Change"],
    "detail": {
      "alarmName": ["IncidentDetected"],
      "state": {
        "value": ["ALARM"]
      }
    }
  }' \
  --description "Aciona o Step Function de incidentes quando o alarme do CloudWatch dispara"

Exemplos de Payload

{
  "version": "0",
  "id": "8bb5a117-e497-cc0b-8d78-0e918d33d409",
  "detail-type": "CloudWatch Alarm State Change",
  "source": "aws.cloudwatch",
  "account": "905418102592",
  "time": "2025-10-01T01:54:12Z",
  "region": "us-east-1",
  "resources": [
    "arn:aws:cloudwatch:us-east-1:905418102592:alarm:Incident Metric Alarm"
  ],
  "detail": {
    "alarmName": "Incident Metric Alarm",
    "state": {
      "value": "ALARM",
      "reason": "Threshold Crossed: 1 out of the last 1 datapoints [2.0 (01/10/25 01:53:00)] was greater than or equal to the threshold (1.0) (minimum 1 datapoint for OK -> ALARM transition).",
      "reasonData": "{\"version\":\"1.0\",\"queryDate\":\"2025-10-01T01:54:12.303+0000\",\"startDate\":\"2025-10-01T01:53:00.000+0000\",\"statistic\":\"Sum\",\"period\":60,\"recentDatapoints\":[2.0],\"threshold\":1.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2025-10-01T01:53:00.000+0000\",\"sampleCount\":2.0,\"value\":2.0}]}",
      "timestamp": "2025-10-01T01:54:12.304+0000"
    },
    "previousState": {
      "value": "INSUFFICIENT_DATA",
      "reason": "Unchecked: Initial alarm creation",
      "timestamp": "2025-10-01T01:52:11.127+0000"
    },
    "configuration": {
      "metrics": [
        {
          "id": "44cccebc-26bb-b9ff-92f4-87b2e87eb077",
          "metricStat": {
            "metric": {
              "namespace": "IncidentMonitoring",
              "name": "ErrorCount",
              "dimensions": {}
            },
            "period": 60,
            "stat": "Sum"
          },
          "returnData": true
        }
      ]
    }
  }
}
{
   "metricFilters": [
      {
         "applyOnTransformedLogs": boolean,
         "creationTime": number,
         "emitSystemFieldDimensions": [ "string" ],
         "fieldSelectionCriteria": "string",
         "filterName": "string",
         "filterPattern": "string",
         "logGroupName": "string",
         "metricTransformations": [
            {
               "defaultValue": number,
               "dimensions": {
                  "string" : "string"
               },
               "metricName": "string",
               "metricNamespace": "string",
               "metricValue": "string",
               "unit": "string"
            }
         ]
      }
   ],
   "nextToken": "string"
}

Base do nosso State Machine

{
  "Comment": "Event-driven workflow",
  "StartAt": "ExtractAlarmDetails",
  "States": {
    "ExtractAlarmDetails": {
      "Type": "Pass",
      "Output": {
        "MetricName": "{% $states.input.detail.configuration.metrics[0].metricStat.metric.name %}",
        "MetricNamespace": "{% $states.input.detail.configuration.metrics[0].metricStat.metric.namespace %}"
      },
      "Next": "DescribeMetricFilter",
      "Assign": {
        "StartTime": "{% $parse($states.input.detail.state.reasonData).startDate %}",
        "EndTime": "{% $parse($states.input.detail.state.reasonData).queryDate %}"
      }
    },
    "DescribeMetricFilter": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:cloudwatchlogs:describeMetricFilters",
      "Arguments": {
        "MetricName": "{% $states.input.MetricName %}",
        "MetricNamespace": "{% $states.input.MetricNamespace %}"
      },
      "Output": {
        "LogGroupName": "{% $states.result.MetricFilters[0].LogGroupName %}",
        "FilterPattern": "{% $states.result.MetricFilters.FilterPattern %}"
      },
      "Catch": [
        {
          "ErrorEquals": ["States.ALL"],
          "Next": "HandleMetricFilterError",
          "Output": {
            "error": "{% $states.errorOutput %}"
          }
        }
      ],
      "Next": "FilterLogEvents"
    },
    "HandleMetricFilterError": {
      "Type": "Fail",
      "Cause": "{% $states.errorOutput %}",
      "Error": "MetricFilterError"
    },
    "FilterLogEvents": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:cloudwatchlogs:filterLogEvents",
      "Arguments": {
        "LogGroupName": "{% $states.input.LogGroupName %}",
        "StartTime": "{% $toMillis($StartTime) %}",
        "EndTime": "{% $toMillis($EndTime) %}",
        "FilterPattern": "{% $states.input.FilterPattern %}"
      },
      "Output": {
        "events": "{% $states.result.Events %}"
      },
      "End": true
    }
  },
  "QueryLanguage": "JSONata"
}

Setup Python

mkdir -p strands
cd strands
python -m venv .venv
source .venv/bin/activate
pip install 'strands-agents[openai]' strands-agents-tools python-dotenv
code .

Credenciais

Groq Cloud

AWS

AWS Learner Labs

AWS Learner Labs
GROQ_API_KEY=<GROQ_API_KEY>
AWS_ACCESS_KEY_ID=<ACCESS_KEY>
AWS_SECRET_ACCESS_KEY=<SECRET_KEY>
AWS_SESSION_TOKEN=<SESSION_TOKEN>

Integração Strands Agents com Groq Cloud

model = OpenAIModel(
    client_args={
        "api_key": os.environ.get("GROQ_API_KEY"),
        "base_url": "https://api.groq.com/openai/v1",
    },
    model_id="openai/gpt-oss-20b",
    params={"max_tokens": 2048, "temperature": 0.7},
)

Integração com o Discord

Foto de perfil do App Webhook|300

Foto de perfil do App Webhook

Armazenar suas credenciais de forma segura

aws ssm put-parameter \
  --name "/lambda/analyze-incident/groq-api-key" \
  --value "SUA_CHAVE_GROQ_AQUI" \
  --type SecureString
aws ssm put-parameter \
  --name "/lambda/discord-webhook/url-webhook" \
  --value "https://discord.com/api/webhooks/1234.../abc5..." \
  --type SecureString

Criando uma Layer para a Lambda

mkdir -p analyze-incident/python
cd analyze-incident
pip install \
  --platform manylinux2014_aarch64 \
  --target python/ \
  --python-version 3.10 \
  --only-binary=:all: \
  'strands-agents[openai]'
zip -r analyze-incident-layer.zip python

Código Python da Lambda Multiagente

import os
import json
import boto3
from pydantic import BaseModel, Field
from strands import Agent
from strands.models.openai import OpenAIModel


ssm = boto3.client("ssm")
GROQ_PARAM_NAME = os.environ.get("GROQ_PARAM_ARN")


def get_groq_api_key():
    """Busca a chave de API do AWS Parameter Store. Levanta exceção em caso de erro."""
    if not GROQ_PARAM_NAME:
        raise ValueError("Variável de ambiente GROQ_PARAM_ARN não definida.")

    try:
        param = ssm.get_parameter(Name=GROQ_PARAM_NAME, WithDecryption=True)

        return param["Parameter"]["Value"]
    except Exception as e:
        raise RuntimeError(
            "Não foi possível obter a chave de API do Parameter Store."
        ) from e


def get_groq_model(model_id: str):
    """Inicializa e retorna o modelo Groq. Levanta exceção em caso de erro."""
    api_key = get_groq_api_key()

    return OpenAIModel(
        client_args={
            "api_key": api_key,
            "base_url": "https://api.groq.com/openai/v1",
        },
        model_id=model_id,
        params={"max_tokens": 4096, "temperature": 0.5},
    )


class IncidentReport(BaseModel):
    title: str = Field(..., description="Título do incidente")
    incident_type: str = Field(..., description="Tipo de incidente detectado")
    description: str = Field(..., description="Resumo do incidente")
    diagnosis: str = Field(..., description="Diagnóstico provável")


log_analyzer = Agent(
    name="Log Analyzer Agent",
    model=get_groq_model("openai/gpt-oss-120b"),
    system_prompt=(
        "Você é um especialista em análise de logs. "
        "Receberá um conjunto de logs como entrada e deve identificar possíveis incidentes, "
        "anomalias ou falhas relevantes."
    ),
)

report_synthesizer = Agent(
    name="Report Synthesizer Agent",
    model=get_groq_model("openai/gpt-oss-20b"),
    system_prompt=(
        "Você é um especialista em relatórios de incidentes. "
        "Com base na análise recebida, gere um relatório no formato estruturado IncidentReport. "
        "Use no máximo 2000 caracteres ao converter para string. "
        "Foque mais na parte do diagnóstico do incidente."
    ),
)


def lambda_handler(event, context):
    logs = event.get("events", [])

    if not logs:
        return {
            "statusCode": 400,
            "body": json.dumps({"error": "Nenhum log fornecido no evento"})
        }

    analysis = log_analyzer(json.dumps(logs))

    report: IncidentReport = report_synthesizer.structured_output(IncidentReport, str(analysis))

    return {
        "statusCode": 200,
        "body": json.dumps({
            "report": report.model_dump()
        })
    }

Código Python da Lambda do Discord Webhook

import os
import json
import boto3
import urllib3
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

http = urllib3.PoolManager()
ssm = boto3.client("ssm")

def get_webhook_url():
    try:
        param_name = os.environ["DISCORD_WEBHOOK_PARAM"]
        response = ssm.get_parameter(Name=param_name, WithDecryption=True)
        return response["Parameter"]["Value"]
    except Exception as e:
        logger.exception("ERRO CRÍTICO: Não foi possível obter a Webhook URL do SSM.")
        raise e

WEBHOOK_URL = get_webhook_url()

def parse_sns_message(sns_message_str: str) -> dict:
    try:
        data = json.loads(sns_message_str)
        if "report" in data and isinstance(data["report"], str):
            data["report"] = json.loads(data["report"])
        return data
    except json.JSONDecodeError:
        logger.warning("Mensagem SNS não é um JSON válido. Tratando como texto puro.")
        return {"raw_message": sns_message_str}

def format_discord_message(data: dict) -> str:
    if "report" in data:
        report = data["report"]
        return (
            f"🚨 **Novo Incidente Detectado** 🚨\n\n"
            f"**Título:** {report.get('title', 'N/A')}\n"
            f"**Tipo:** {report.get('incident_type', 'N/A')}\n"
            f"**Descrição:** {report.get('description', 'N/A')}\n"
            f"**Diagnóstico:** {report.get('diagnosis', 'N/A')}"
        )

    raw_message = data.get("raw_message") or json.dumps(data, indent=2)
    return f"📢 **Notificação SNS Recebida**:\n```json\n{raw_message}\n```"

def send_to_discord(message: str):
    payload = {"content": message}
    encoded_body = json.dumps(payload).encode("utf-8")

    response = http.request(
        "POST",
        WEBHOOK_URL,
        body=encoded_body,
        headers={"Content-Type": "application/json"}
    )

    if response.status not in (200, 204):
        error_message = f"Falha ao enviar para o Discord: {response.status} - {response.data.decode()}"
        logger.error(error_message)
        raise RuntimeError(error_message)

    logger.info(f"Mensagem enviada ao Discord com sucesso. Status: {response.status}")

def lambda_handler(event, context):
    logger.info(f"Evento recebido: {json.dumps(event)}")

    try:
        sns_message_str = event["Records"][0]["Sns"]["Message"]
        parsed_data = parse_sns_message(sns_message_str)
        discord_message = format_discord_message(parsed_data)
        send_to_discord(discord_message)

        return {
            "statusCode": 200,
            "body": json.dumps({"message": "Mensagem enviada ao Discord com sucesso."})
        }

    except (KeyError, IndexError) as e:
        logger.error(f"Erro ao extrair mensagem do evento SNS: {e}")
        return {"statusCode": 400, "body": "Formato de evento SNS inválido."}
    except Exception:
        logger.exception("Ocorreu um erro inesperado durante a execução.")
        raise

JSONata do PutObject S3

{
  "Body": "{% $parse($states.input.body).report %}",
  "Bucket": "reports-<MATRICULA>",
  "Key": "{% 'report-' & $string($now()) & '.json' %}"
}

Comandos para testar o Alarme

1. Lambda Function

aws logs create-log-stream \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "lambda/$(date +%Y-%m-%d)"
aws logs put-log-events \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "lambda/$(date +%Y-%m-%d)" \
  --log-events '[
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[LAMBDA] START RequestId: a1b2c3d4-5678-90ab-cdef-1234567890ab Version: $LATEST"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[LAMBDA] INFO: Processando evento de incidente - severity: HIGH"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[LAMBDA] ERROR: Failed to connect to Groq API - Connection timeout after 30s"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[LAMBDA] ERROR: Retry attempt 3/3 failed - giving up"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[LAMBDA] END RequestId: a1b2c3d4-5678-90ab-cdef-1234567890ab"
    }
  ]'

2. RDS Database

aws logs create-log-stream \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "rds/$(date +%Y-%m-%d)"
aws logs put-log-events \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "rds/$(date +%Y-%m-%d)" \
  --log-events '[
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[RDS] '"$(date +%Y-%m-%d)"' ERROR: deadlock detected"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[RDS] '"$(date +%Y-%m-%d)"' DETAIL: Process 12346 waits for ShareLock on transaction 98765"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[RDS] '"$(date +%Y-%m-%d)"' ERROR: could not serialize access due to concurrent update"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[RDS] '"$(date +%Y-%m-%d)"' FATAL: remaining connection slots are reserved for superuser"
    }
  ]'

3. ECS Container

aws logs create-log-stream \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "ecs/$(date +%Y-%m-%d)"
aws logs put-log-events \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "ecs/$(date +%Y-%m-%d)" \
  --log-events '[
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[ECS] INFO: Application started on port 8080"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[ECS] WARN: High memory usage detected: 85% of 2GB limit"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[ECS] ERROR: Connection pool exhausted: max 50 connections reached"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[ECS] ERROR: Database query timeout after 5000ms"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[ECS] FATAL: Container shutting down due to OOMKilled"
    }
  ]'

4. API Gateway

aws logs create-log-stream \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "api-gateway/$(date +%Y-%m-%d)"
aws logs put-log-events \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "api-gateway/$(date +%Y-%m-%d)" \
  --log-events '[
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[API-GW] (req-123) Method request path: /api/incidents"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[API-GW] (req-123) ERROR: Execution failed - Malformed Lambda proxy response"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[API-GW] (req-123) Method completed with status: 502"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[API-GW] (req-124) ERROR: Throttle limit exceeded - Too Many Requests"
    }
  ]'

5. EC2 System

aws logs create-log-stream \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "ec2/$(date +%Y-%m-%d)"
aws logs put-log-events \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "ec2/$(date +%Y-%m-%d)" \
  --log-events '[
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[EC2] '"$(date +%Y-%m-%d)"' kernel: ERROR: Out of memory - Kill process 9876 (java) score 850"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[EC2] '"$(date +%Y-%m-%d)"' sshd: ERROR: Failed password for invalid user admin from 203.0.113.42"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[EC2] '"$(date +%Y-%m-%d)"' nginx: [ERROR] connect() failed (111: Connection refused)"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[EC2] '"$(date +%Y-%m-%d)"' disk-monitor: CRITICAL ERROR - Disk usage: 95%"
    }
  ]'

6. Step Functions

aws logs create-log-stream \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "stepfunctions/$(date +%Y-%m-%d)"
aws logs put-log-events \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "stepfunctions/$(date +%Y-%m-%d)" \
  --log-events '[
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[STEP-FN] {\"type\":\"ExecutionStarted\",\"input\":\"{\\\"severity\\\":\\\"HIGH\\\"}\"}"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[STEP-FN] {\"type\":\"TaskStateEntered\",\"name\":\"FilterEvent\"}"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[STEP-FN] {\"type\":\"LambdaFunctionFailed\",\"error\":\"ERROR: TimeoutError - Task timed out after 60 seconds\"}"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[STEP-FN] {\"type\":\"ExecutionFailed\",\"cause\":\"ERROR: Lambda function failed\"}"
    }
  ]'

7. Application Load Balancer

aws logs create-log-stream \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "alb/$(date +%Y-%m-%d)"
aws logs put-log-events \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "alb/$(date +%Y-%m-%d)" \
  --log-events '[
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[ALB] http '"$(date +%Y-%m-%d)"' app/prod-alb/abc123 203.0.113.42:54321 10.0.1.23:80 0.001 0.002 0.000 200 200 512 1024"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[ALB] ERROR http '"$(date +%Y-%m-%d)"' app/prod-alb/abc123 198.51.100.25:12345 10.0.1.23:80 0.003 5.234 0.001 504 504 2048 0"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[ALB] ERROR http '"$(date +%Y-%m-%d)"' app/prod-alb/abc123 192.0.2.156:23456 - -1 -1 -1 502 - 1024 0"
    }
  ]'

8. CloudFront

aws logs create-log-stream \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "cloudfront/$(date +%Y-%m-%d)"
aws logs put-log-events \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "cloudfront/$(date +%Y-%m-%d)" \
  --log-events '[
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[CLOUDFRONT] '"$(date +%Y-%m-%d)"' IAD89 12345 203.0.113.42 GET example.com /api/data 200"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[CLOUDFRONT] ERROR '"$(date +%Y-%m-%d)"' IAD89 12346 198.51.100.25 GET example.com /api/data 504 GatewayTimeout"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[CLOUDFRONT] ERROR '"$(date +%Y-%m-%d)"' IAD89 12347 192.0.2.156 GET example.com /api/data 403 AccessDenied"
    }
  ]'

9. DynamoDB

aws logs create-log-stream \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "dynamodb/$(date +%Y-%m-%d)"
aws logs put-log-events \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "dynamodb/$(date +%Y-%m-%d)" \
  --log-events '[
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[DYNAMODB] ERROR: ProvisionedThroughputExceededException - Rate of requests exceeds provisioned throughput"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[DYNAMODB] ERROR: ConditionalCheckFailedException - The conditional request failed"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[DYNAMODB] ERROR: ThrottlingException - Rate exceeded for table users-table"
    }
  ]'

10. S3 Access Logs

aws logs create-log-stream \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "s3/$(date +%Y-%m-%d)"
aws logs put-log-events \
  --log-group-name /minicurso/cloud-incident \
  --log-stream-name "s3/$(date +%Y-%m-%d)" \
  --log-events '[
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[S3] production-bucket ['"$(date +%Y-%m-%d)"'] 203.0.113.42 REST.GET.OBJECT data.json 200"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[S3] ERROR production-bucket ['"$(date +%Y-%m-%d)"'] 198.51.100.25 REST.GET.OBJECT secret.json 403 AccessDenied"
    },
    {
      "timestamp": '"$(date +%s%3N)"',
      "message": "[S3] ERROR production-bucket ['"$(date +%Y-%m-%d)"'] 192.0.2.100 REST.PUT.OBJECT large-file.zip 500 InternalError"
    }
  ]'


Próximo Post
Instalação e Configuração do Kind