Обзор модов Чанка 3
Бэкенд-моды расширяют базовый счётчик посещений, превращая его в демонстрацию специализированных навыков.
Developer Mod: Schemas
Задача
Добавить валидацию API с помощью JSON Schema или OpenAPI. Документировать API.
Реализация: OpenAPI спецификация
# openapi.yaml
openapi: 3.0.3
info:
title: Cloud Resume API
description: Visitor counter API for Cloud Resume Challenge
version: 1.0.0
servers:
- url: https://api.ivanpetrov.com
paths:
/count:
get:
summary: Get and increment visitor count
operationId: getCount
responses:
'200':
description: Current visitor count
content:
application/json:
schema:
type: object
properties:
count:
type: integer
minimum: 0
example: 42
required:
- count
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Error:
type: object
properties:
error:
type: string
example: "Internal server error"
Валидация в Lambda
import json
from jsonschema import validate, ValidationError
RESPONSE_SCHEMA = {
"type": "object",
"required": ["count"],
"properties": {
"count": {"type": "integer", "minimum": 0}
}
}
def lambda_handler(event, context):
count = get_and_increment()
body = {"count": count}
# Validate response before sending
try:
validate(instance=body, schema=RESPONSE_SCHEMA)
except ValidationError as e:
return {
'statusCode': 500,
'body': json.dumps({'error': f'Response validation failed: {e.message}'})
}
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps(body)
}
DevOps Mod: Monitor Lizard
Задача
Настроить мониторинг и алертинг для serverless-функций. Создать дашборд с ключевыми метриками.
Реализация: CloudWatch Dashboard
# Создание CloudWatch алармов
aws cloudwatch put-metric-alarm \
--alarm-name "crc-lambda-errors" \
--metric-name Errors \
--namespace AWS/Lambda \
--statistic Sum \
--period 300 \
--threshold 5 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 1 \
--dimensions Name=FunctionName,Value=visitor-counter \
--alarm-actions arn:aws:sns:us-east-1:123456789012:crc-alerts
aws cloudwatch put-metric-alarm \
--alarm-name "crc-lambda-duration" \
--metric-name Duration \
--namespace AWS/Lambda \
--statistic Average \
--period 300 \
--threshold 3000 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 2 \
--dimensions Name=FunctionName,Value=visitor-counter
Custom Metrics
import boto3
cloudwatch = boto3.client('cloudwatch')
def lambda_handler(event, context):
count = get_and_increment()
# Custom metric: visitor count
cloudwatch.put_metric_data(
Namespace='CRC/VisitorCounter',
MetricData=[{
'MetricName': 'VisitorCount',
'Value': count,
'Unit': 'Count'
}]
)
return {'statusCode': 200, 'body': json.dumps({'count': count})}
Security Mod: Check Privilege
Задача
Реализовать минимальные IAM-привилегии для каждого компонента. Документировать модель угроз.
Реализация: Granular IAM Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DynamoDBSpecificTable",
"Effect": "Allow",
"Action": [
"dynamodb:UpdateItem",
"dynamodb:GetItem"
],
"Resource": "arn:aws:dynamodb:us-east-1:*:table/visitor-counter",
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["visitors"]
}
}
},
{
"Sid": "CloudWatchLogs",
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:us-east-1:*:log-group:/aws/lambda/visitor-counter:*"
}
]
}
Модель угроз для CRC
Угроза | Вероятность | Влияние | Митигация
────────────────────────┼─────────────┼─────────┼──────────────────
DDoS на API | Средняя | Среднее | Rate limiting, WAF
SQL Injection | Низкая | Высокое | NoSQL, валидация
Утечка ключей | Средняя | Высокое | IAM Role, нет ключей в коде
Неавторизованный доступ | Низкая | Среднее | IAM least privilege
Инфляция счётчика | Низкая | Низкое | Rate limiting
Architect Mod: Choose Your Layer
Задача
Сравнить serverless vs контейнеры vs VM для бэкенда CRC. Анализ стоимости при разных нагрузках.
Анализ стоимости
Нагрузка: 100,000 запросов/месяц, 200 мс среднее время
Lambda (128 MB):
Compute: 100K * 0.2s * 128MB/1024 = 2.5 GB-sec = $0.00 (Free Tier)
Requests: 100K = $0.00 (Free Tier)
Итого: $0.00
Fargate (0.25 vCPU, 0.5 GB):
Compute: $0.25 * 720h = $9.12/мес
Итого: $9.12/мес
EC2 (t3.micro):
Instance: $0.0104/час * 720h = $7.49/мес
Итого: $7.49/мес
При 100M запросов/мес:
Lambda: ~$20/мес
Fargate: ~$9/мес (тот же контейнер)
EC2: ~$7.50/мес (тот же инстанс)
Вывод: Lambda экономичнее при низких нагрузках, контейнеры/VM -- при высоких и постоянных.
Data Engineer Mod: Count Things
Задача
Реализовать несколько типов счётчиков и агрегаций: по странице, по дню, по источнику трафика.
Реализация: расширенная схема DynamoDB
from datetime import datetime, timezone
from decimal import Decimal
def lambda_handler(event, context):
now = datetime.now(timezone.utc)
today = now.strftime('%Y-%m-%d')
page = event.get('queryStringParameters', {}).get('page', '/')
referrer = event.get('headers', {}).get('referer', 'direct')
source = extract_domain(referrer) if referrer != 'direct' else 'direct'
# 1. Total counter
total = increment_counter('total-visitors')
# 2. Daily counter
increment_counter(f'daily-{today}')
# 3. Page counter
increment_counter(f'page-{page}')
# 4. Source counter
increment_counter(f'source-{source}')
return {
'statusCode': 200,
'body': json.dumps({
'count': total,
'date': today
})
}
def increment_counter(counter_id):
response = table.update_item(
Key={'id': counter_id},
UpdateExpression='ADD #c :val',
ExpressionAttributeNames={'#c': 'count'},
ExpressionAttributeValues={':val': Decimal('1')},
ReturnValues='UPDATED_NEW'
)
return int(response['Attributes']['count'])
AI Engineer Mod: Make it Sentient
Задача
Создать chatbot, который отвечает на вопросы о вашем резюме и опыте, используя RAG (Retrieval-Augmented Generation).
Реализация: RAG с Bedrock
import boto3
import json
bedrock = boto3.client('bedrock-runtime')
RESUME_CONTEXT = """
Иван Петров, Cloud Engineer. 2 года опыта в AWS.
Сертификации: AWS Cloud Practitioner, AWS SAA.
Навыки: Python, Terraform, Lambda, DynamoDB, CloudFormation.
Проекты: Cloud Resume Challenge с serverless бэкендом.
"""
def lambda_handler(event, context):
body = json.loads(event.get('body', '{}'))
question = body.get('question', '')
if not question:
return {'statusCode': 400, 'body': json.dumps({'error': 'No question'})}
prompt = f"""Based on this resume, answer the question.
Resume: {RESUME_CONTEXT}
Question: {question}
Answer concisely in 2-3 sentences."""
response = bedrock.invoke_model(
modelId='anthropic.claude-3-haiku-20240307-v1:0',
body=json.dumps({
'anthropic_version': 'bedrock-2023-05-31',
'max_tokens': 256,
'messages': [{'role': 'user', 'content': prompt}]
})
)
result = json.loads(response['body'].read())
answer = result['content'][0]['text']
return {
'statusCode': 200,
'headers': {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
'body': json.dumps({'answer': answer})
}
Выбор мода: что делать
| Если вы целитесь в... | Мод бэкенда | Сложность |
|---|---|---|
| Cloud Developer | Schemas (OpenAPI) | Средняя |
| DevOps/SRE | Monitor Lizard | Средняя |
| Security Engineer | Check Privilege | Высокая |
| Solutions Architect | Choose Your Layer | Средняя |
| Data Engineer | Count Things | Средняя |
| AI Engineer | Make it Sentient | Высокая |