Monitoring as Code: як ми перевірили, що сайт працює?

🔧 Цього тижня ми провели заключний практичний воркшоп з благодійної серії AWS & Terraform & GitLab від DevOps 01.
Нагадую, як усе було:
👉 1-й воркшоп - розібрали React-based аплікейшн на атоми, підготували інфраструктуру в AWS (CloudFront, S3, Route53, ACM)
👉 2-й воркшоп - написання Terraform-ресурсів + імпорт у стейт
👉 3-й воркшоп - CI/CD як для application repo, так і для Terraform repo
AWS Architecture
🔍 Наче основні компоненти у нас присутні
✅ Є аплікейшн
✅ Ми знаємо технічний стек
✅ Розуміємо його бізнес-логіку
✅ Вміємо автоматично збирати за комітом у репозиторій та робити деплоймент в AWS environment, який покритий Terraform-кодом зі своїм CI/CD
Але як ми дізнаємося, що наш сайт успішно працює?
problem statement
📌 Дотримуючись нашого принципу - рухатися від PoC до MVP - можна написати Python-скрипт, який використовує бібліотеку requests.
Завдяки їй ми можемо відправляти HTTP-запити, а потім оперувати інформацією з response, щоб зробити висновок: працює сайт чи ні.
import os
import logging
import requests
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def main():
url = os.environ.get("TARGET_URL")
if not url:
logger.error("TARGET_URL not set")
return
try:
response = requests.get(url, timeout=5)
if response.status_code != 200:
logger.warning(f"Site is down: {url} returned {response.status_code}")
else:
logger.info(f"Site is up: {url} returned {response.status_code}")
except Exception as e:
logger.error(f"Site unreachable: {e}")
if __name__ == "__main__":
main()

📨 Далі залишається визначитися, що ми будемо робити з цією інформацією
Бо моніторинг - це не лише перевірка endpoints та оперування метриками. Це ще й notifications для тих, хто має бути в курсі: чи живий сайт, чи ні?
У рамках PoC можемо почати з email-повідомлень.
import os
import smtplib
import logging
import requests
from email.message import EmailMessage
logger = logging.getLogger()
logger.setLevel(logging.INFO)
SMTP_SERVER = os.environ.get("SMTP_SERVER")
SMTP_PORT = int(os.environ.get("SMTP_PORT", 587))
SMTP_USER = os.environ.get("SMTP_USER")
SMTP_PASS = os.environ.get("SMTP_PASS")
def send_alert_emails(subject, message):
emails = os.environ.get("ALERT_EMAILS", "")
recipient_list = [email.strip() for email in emails.split(",") if email.strip()]
msg = EmailMessage()
msg["From"] = SMTP_USER
msg["Subject"] = subject
msg.set_content(message)
try:
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
server.starttls()
server.login(SMTP_USER, SMTP_PASS)
for recipient in recipient_list:
msg["To"] = recipient
server.send_message(msg)
logger.info(f"Email sent to {recipient}")
del msg["To"]
except Exception as e:
logger.error(f"Failed to send email: {e}")
def main():
url = os.environ.get("TARGET_URL")
if not url:
logger.error("TARGET_URL not set")
return
try:
response = requests.get(url, timeout=5)
if response.status_code != 200:
send_alert_emails("Site is down", f"{url} returned {response.status_code}")
except Exception as e:
send_alert_emails("Site unreachable", str(e))
if __name__ == "__main__":
main()
monitoring PoC
📅 Як часто перевіряти наш сайт?
Нам потрібен якийсь розклад. Наприклад, schedule у стилі crontab.
🤔 Але де запускати цей код?
- Контейнер?
- Віртуалка?
Це вже тягне за собою необхідність зібрати службовий імедж, десь його запустити (або взагалі тягнути Prometheus + Blackbox exporter), адмініструвати цю інфраструктуру…

🧠 Тут на допомогу приходить AWS Lambda - класичний представник Serverless Managed Services, який працює за простою моделлю:
🔹 ми платимо AWS за час виконання коду,
🔹 а все інше AWS зробить за нас.
import os
import logging
import requests
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
url = os.environ.get("TARGET_URL")
try:
response = requests.get(url, timeout=5)
if response.status_code != 200:
send_alert_emails("Site is down", f"{url} returned {response.status_code}")
except Exception as e:
send_alert_emails("Site unreachable", str(e))

Нам залишається лише:
✅ створити Lambda function
✅ обрати runtime (python3.13)
✅ визначити Lambda execution IAM role
Але не забуваймо - Lambda by design не має всіх dependencies у середовищі. Тому для requests використовуємо Lambda Layers, куди закидаємо бібліотеку окремо.
#підготовка zip для AWS Lambda Layer
mkdir requests-layer && cd requests-layer
pip install requests -t python
zip -r ../requests-layer.zip python
Lambda layers
Як надсилаємо emails?
📤 Надсилати email будемо через AWS SES - керований сервіс для автоматизації email workflow.
Що треба:
🔹 налаштувати email identity, з якої будемо надсилати листи
🔹 взаємодіяти з SES з Lambda-коду через boto3 (AWS SDK for Python)
🔹 не забути додати в IAM role Lambda дозвіл на доступ до SES
AWS SES
#lambda/lambda_function.py
import os
import logging
import requests
import boto3
logger = logging.getLogger()
logger.setLevel(logging.INFO)
ses = boto3.client('ses')
def send_alert_emails(subject, message):
emails = os.environ.get("ALERT_EMAILS", "")
recipient_list = [email.strip() for email in emails.split(",") if email.strip()]
for email in recipient_list:
ses.send_email(
Source=email,
Destination={"ToAddresses": [email]},
Message={
"Subject": {"Data": subject},
"Body": {"Text": {"Data": message}}
}
)
def lambda_handler(event, context):
url = os.environ.get("TARGET_URL")
try:
response = requests.get(url, timeout=5)
if response.status_code != 200:
send_alert_emails("Site is down", f"{url} returned {response.status_code}")
except Exception as e:
send_alert_emails("Site unreachable", str(e))
🧩 На цей момент ми покрили
- запуск Python-коду за допомогою AWS Lambda
- додавання залежностей з PyPI через Lambda Layer
- надсилання email через AWS SES
⏱️ Залишилося вирішити лише питання розкладу
Тут нам допоможе AWS EventBridge:
🔹 Lambda можна викликати або через HTTP endpoint (вручну), або через тригери
🔹 Ми обираємо EventBridge schedule rule - rate(2 minutes) або cron(* * * * *)
🔹 Прив’язуємо правило до Lambda та дозволяємо виклик
📝 Логи роботи функції автоматично потрапляють у CloudWatch Log Group.

І нарешті - описуємо все в Terraform-коді (можна своїм модулем або скористатися готовим модулем від Anton Babenko).
module "lambda_site_checker" {
source = "terraform-aws-modules/lambda/aws"
version = "~> 7.0"
function_name = "site_checker_v3"
handler = "lambda_function.lambda_handler"
runtime = "python3.13"
source_path = "./lambda"
create_package = true
environment_variables = {
TARGET_URL = var.target_url
ALERT_EMAILS = var.alert_emails
}
layers = [data.aws_lambda_layer_version.requests.arn]
create_current_version_allowed_triggers = false
cloudwatch_logs_retention_in_days = 14
allowed_triggers = {
cloudwatch = {
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.site_checker_trigger.arn
}
}
attach_policy = false
policy = aws_iam_policy.ses_send_email.arn
}

Ось так, крок за кроком, ми рухаємося від ідеї до повноцінного MVP.
Серія воркшопів була частиною ініціативи DevOps01, і я дякую всім, хто приєднався або підтримав 💛
Основної мети досягнуто - ми зібрали гроші для ЗСУ та навчилися чогось нового!
Окрема подяка TEMABIT Software Development та Stanislav Kolenkin за технічну підтримку DevOps 01.
Посилання
Lambda
- https://github.com/terraform-aws-modules/terraform-aws-lambda
- https://docs.aws.amazon.com/lambda/latest/dg/welcome.html
- https://docs.aws.amazon.com/lambda/latest/dg/lambda-python.html
- https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html
- https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html
- https://docs.aws.amazon.com/lambda/latest/dg/lambda-invocation.html
- https://docs.aws.amazon.com/lambda/latest/dg/lambda-services.html
EventBridge->Lambda
SES
#AWSCommunity #DevOps01
Вперше опубліковано на LinkedIn 12 квітня 2025 р.: оригінал.