Ось повноцінний урок, створений спеціально для вас у стилі David Malan (CS50). Уявіть, що ви сидите в лекційній залі Гарварду (або дивитесь стрім на YouTube), я ходжу сценою, активно жестикулюю, і ми розбираємося з тим, як змусити Celery працювати в океані Kubernetes.
🎓 Тема: Celery у Kubernetes (Огляд)
Привіт, друзі! Радий бачити вас усіх. Сьогодні ми поговоримо про те, що відбувається, коли наш код виростає з "домашнього ноутбука" і переїжджає у великий світ хмарних технологій.
1. 🔥 Вступ: Коли одного кухаря замало
Уявіть, що ви відкрили піцерію. У вас є один геніальний кухар (назвемо його Web Server), який приймає замовлення на касі.
Коли клієнт каже: "Мені Пепероні", кухар записує замовлення і... біжить на кухню пекти піцу. Клієнт чекає біля каси 15 хвилин. Черга за ним росте. Люди зляться. Бізнес страждає. Чому? Тому що той, хто приймає замовлення, не повинен його виконувати одночасно.
Ви вирішуєте проблему: наймаєте помічників на кухню. Тепер касир (Web) лише кричить: "Одне Пепероні!", кидає чек у кошик (Message Broker), а кухарі на кухні (Celery Workers) підхоплюють ці чеки і печуть.
Але ось настає Чорна п’ятниця. Замовлень тисячі! Ваша кухня захлинається. Вам потрібно миттєво, просто зараз, найняти ще 50 кухарів, а коли вечір закінчиться — звільнити їх, щоб не платити зарплату дарма. Вручну це робити — божевілля.
Ось тут на сцену виходить Kubernetes (K8s). Це ваш автоматичний менеджер ресторану. Він дивиться на навантаження і клацанням пальців створює нових кухарів (Workers), розставляє їх по місцях, а якщо хтось із них знепритомнів від жари — замінює на нового.
Питання до вас: Як нам запакувати цього "кухаря" (Celery Worker) так, щоб Kubernetes міг клонувати його сотні разів без нашої участі? І як зробити так, щоб вони не заважали один одному?
Саме про це ми сьогодні й поговоримо. Без цього знання будь-який серйозний Python-проєкт впаде під першим же навантаженням.
2. 🧠 Теоретична база: Що "під капотом"?
Давайте розкладемо це на прості цеглинки. Не зубримо, а розуміємо логіку.
Ключові гравці:
- Container (Docker Image): Це ваша "уніформа кухаря". У ній запакований код вашого проєкту, бібліотеки Python і команда запуску Celery.
- Pod (Под): У світі Kubernetes це найменша одиниця. Уявіть, що це окремий робочий стіл на кухні. У нашому випадку в одному Поді працює один процес Celery Worker.
- Deployment (Деплоймент): Це інструкція для менеджера (K8s). Ви кажете: "Мені потрібно, щоб завжди працювало 3 копії мого Celery Worker. Якщо один впаде — підніми нового".
- Broker (Redis/RabbitMQ): Це дошка оголошень, куди падають задачі. Вона зазвичай живе окремо від воркерів (або як окремий сервіс у K8s, або в хмарі).
Як це працює (Flow):
- Web-додаток (наприклад, Django/FastAPI) створює задачу і кидає її в Broker.
- Kubernetes запустив, скажімо, 10 Подів із Celery.
- Кожен Под постійно "стукає" до Брокера: "Є робота? Є робота?".
- Хто перший вхопив задачу — той її виконує.
- Якщо Под "помирає" (наприклад, закінчилася пам'ять), Kubernetes бачить це і миттєво запускає новий чистий Под.
❗️ Що треба запам’ятати залізно: Celery Worker у Kubernetes не повинен зберігати стан (stateless). Якщо воркер зберіг файл на свій диск і помер — файл зник назавжди. Усі результати пишемо в базу даних або S3!
3. 🧪 Приклади: Від коду до інфраструктури
Крок 1: Мінімальний Dockerfile
Перед тим як йти в Kubernetes, нам треба зібрати образ.
Що ви очікуєте побачити в команді запуску? (Пауза... так, саме команду celery).
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
# Ось наша магія. Ми не запускаємо тут веб-сервер.
# Ми запускаємо воркера.
CMD ["celery", "-A", "my_project", "worker", "--loglevel=info"]
Крок 2: Kubernetes Deployment (Спрощено)
Тепер найцікавіше. Як сказати K8s запустити це? Ми пишемо YAML-файл. Як ви думаєте, скільки реплік (копій) нам потрібно для старту? Давайте візьмемо 2.
apiVersion: apps/v1
kind: Deployment
metadata:
name: celery-worker
spec:
replicas: 2 # <--- Кількість кухарів
selector:
matchLabels:
app: celery
template:
metadata:
labels:
app: celery
spec:
containers:
- name: celery
image: my-registry/my-app:latest
command: ["celery", "-A", "my_project", "worker", "--loglevel=info"]
env:
# Важливо! Воркер має знати, де Брокер.
- name: CELERY_BROKER_URL
value: "redis://redis-service:6379/0"
Що тут відбулося? Ми сказали K8s: "Візьми цей образ, запусти 2 копії. І ось адреса Redis, щоб вони знали, звідки брати задачі".
Крок 3: Чому це круто (Scaling)
Уявимо, що настав пік навантаження. Що ми робимо? Ми не переписуємо код. Ми просто кажемо Kubernetes:
kubectl scale deployment celery-worker --replicas=10
Бум! 💥 За кілька секунд у вас працює 10 воркерів замість 2. Черга задач розсмоктується миттєво. Коли пік спав:
kubectl scale deployment celery-worker --replicas=2
І ми заощадили гроші на серверах. Це і є сила хмар.
4. 🛠 Практична частина
Час закачати рукави. Уявіть, що ви DevOps-інженер на проєкті.
Завдання 1: Детектив
Ви запустили Deployment, але поди мають статус CrashLoopBackOff. Вони запускаються і одразу падають.
Питання: Яка найімовірніша причина, пов'язана зі змінними оточення (Environment Variables)?
(Підказка: чи знає воркер, де знаходиться Redis, якщо ми забули передати CELERY_BROKER_URL?)
Завдання 2: "А що, якщо..."
Напишіть (на папері або подумки), як зміниться наш YAML-файл, якщо ми хочемо, щоб один набір воркерів обробляв тільки "важкі" задачі (черга heavy), а інший — тільки "легкі" (light)?
(Підказка: це змінюється в аргументах команди запуску celery ... -Q ...)
Завдання 3: Ресурсний голод Ваш воркер обробляє зображення і іноді "з'їдає" 2 ГБ оперативної пам'яті. Але в Kubernetes ви встановили ліміт 500 МБ. Що зробить Kubernetes з цим подом? (Він його вб'є: OOMKilled). Як це виправити в YAML?
Завдання 4: Міні-кейс Вам треба оновити код воркера. Ви робите новий деплой. Як зробити так, щоб старі воркери не кинули задачу на півдорозі, а спочатку дорабили її, а вже потім вимкнулися? (Гуглити: Graceful Shutdown Celery Kubernetes).
5. 💡 Мислення як у розробника
Як відрізнити новачка від профі при роботі з Celery в K8s?
-
Новачок думає: "Запущу все в одному контейнері: і Django, і Celery, і Redis".
- Профі знає: Це порушує філософію Docker. Один процес — один контейнер. Це дозволяє скейлити воркерів окремо від веб-сайту.
-
Новачок думає: "У мене завис воркер, перезавантажу сервер".
- Профі використовує Liveness Probes. Це механізм K8s, який періодично "тикає" воркера паличкою: "Ти живий?". Якщо воркер завис (deadlock), K8s сам його перезавантажить. Вам навіть прокидатися вночі не треба.
-
Типова помилка: Втрата задач при перезапуску.
- Порада: Використовуйте
acks_late=Trueу Celery. Це означає: "Підтверджую виконання задачі тільки після того, як вона реально виконана". Якщо Под впаде під час роботи, задача повернеться в чергу і її підхопить інший Под.
- Порада: Використовуйте
6. 🧩 Підсумок
Отже, що ми сьогодні зробили? Ми взяли нашого "кухаря" (Celery), клонували його за допомогою магії Kubernetes і навчилися керувати цією армією.
Тепер ви вмієте: * ✅ Розуміти роль Celery Worker як окремого Пода. * ✅ Писати базовий маніфест для розгортання воркера. * ✅ Розуміти, як масштабувати обробку фонових задач однією командою.
Наступного разу: Ми підемо ще далі. Що, якби Kubernetes сам дивився на довжину черги в Redis і додавав воркерів автоматично, без вашої команди kubectl scale?
Це називається HPA (Horizontal Pod Autoscaler) та KEDA. Але це вже зовсім інша історія.
А поки — спробуйте написати свій перший deployment. Це був CS50... тобто, це був урок про Celery в K8s. Побачимось!