Как вы управляете работником с AWS Elastic Beanstalk?
Я запускаю приложение django на эластичном бобовом стебле aws. Я хотел бы запустить фоновое задание или работника, чтобы запустить сельдерей.
Я не могу найти, возможно ли это или нет. Если да, то как это можно достичь?
Вот что я делаю прямо сейчас, но каждый раз это создает ошибку типа события.
container_commands:
01_syncdb:
command: "django-admin.py syncdb --noinput"
leader_only: true
50_sqs_email:
command: "./manage.py celery worker --loglevel=info"
leader_only: true
Ответы
Ответ 1
Как @chris-wheadon предложил в своем комментарии, вы должны попытаться запустить сельдерей в качестве демона на заднем плане. AWS Elastic Beanstalk уже использует supervisord для запуска некоторых процессов deamon. Таким образом, вы можете использовать это для запуска celeryd и избегать создания собственного AMI для этого. Это хорошо работает для меня.
Что я делаю, так это программно добавляю конфигурационный файл celeryd к экземпляру после того, как приложение развернуто в нем EB. Сложность в том, что в файле должны быть установлены необходимые переменные окружения для демона (например, ключи доступа AWS, если вы используете S3 или другие службы в своем приложении).
Ниже приведена копия скрипта, который я использую, добавьте этот скрипт в вашу папку .ebextensions
которая конфигурирует вашу среду EB.
Сценарий установки создает файл в папке /opt/elasticbeanstalk/hooks/appdeploy/post/
(документация), который используется во всех экземплярах EB. Любой сценарий оболочки будет выполнен после развертывания. Размещенный там скрипт оболочки работает следующим образом:
- В
celeryenv
переменного, virutalenv среда хранятся в формате, который следует за supervisord обозначения. Это список переменных env, разделенных запятыми. - Затем скрипт создает переменную
celeryconf
которая содержит файл конфигурации в виде строки, которая включает ранее проанализированные переменные env. - Затем эта переменная
celeryd.conf
в файл с именем celeryd.conf
, файл конфигурации супервизора для демона celeryd.conf
. - Наконец, путь к вновь созданному файлу конфигурации добавляется в основной файл
supervisord.conf
, если его там еще нет.
Вот копия сценария:
files:
"/opt/elasticbeanstalk/hooks/appdeploy/post/run_supervised_celeryd.sh":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
# Get django environment variables
celeryenv='cat /opt/python/current/env | tr '\n' ',' | sed 's/export //g' | sed 's/$PATH/%(ENV_PATH)s/g' | sed 's/$PYTHONPATH//g' | sed 's/$LD_LIBRARY_PATH//g''
celeryenv=${celeryenv%?}
# Create celery configuraiton script
celeryconf="[program:celeryd]
; Set full path to celery program if using virtualenv
command=/opt/python/run/venv/bin/celery worker -A myappname --loglevel=INFO
directory=/opt/python/current/app
user=nobody
numprocs=1
stdout_logfile=/var/log/celery-worker.log
stderr_logfile=/var/log/celery-worker.log
autostart=true
autorestart=true
startsecs=10
; Need to wait for currently executing tasks to finish at shutdown.
; Increase this if you have very long running tasks.
stopwaitsecs = 600
; When resorting to send SIGKILL to the program to terminate it
; send SIGKILL to its whole process group instead,
; taking care of its children as well.
killasgroup=true
; if rabbitmq is supervised, set its priority higher
; so it starts first
priority=998
environment=$celeryenv"
# Create the celery supervisord conf script
echo "$celeryconf" | tee /opt/python/etc/celery.conf
# Add configuration script to supervisord conf (if not there already)
if ! grep -Fxq "[include]" /opt/python/etc/supervisord.conf
then
echo "[include]" | tee -a /opt/python/etc/supervisord.conf
echo "files: celery.conf" | tee -a /opt/python/etc/supervisord.conf
fi
# Reread the supervisord config
supervisorctl -c /opt/python/etc/supervisord.conf reread
# Update supervisord in cache without restarting all services
supervisorctl -c /opt/python/etc/supervisord.conf update
# Start/Restart celeryd through supervisord
supervisorctl -c /opt/python/etc/supervisord.conf restart celeryd
Ответ 2
Я пытался сделать что-то подобное на PHP, но по какой-то причине я не мог заставить рабочего работать. Я переключился на AMI на сервере EC2 и имел успех с тех пор.
Ответ 3
Мне не удалось настроить сервер Django в рабочей среде AWS, вместо этого я использовал сервер Flask. Первоначально я пытался настроить Celery для планирования периодических задач на работника, но я чувствую, что это работает против модели, которую пытается навязать AWS. Я думаю, что "путь AWS" заключается в создании небольшого приложения Flask в рабочей среде. Оттуда вы можете запустить этого работника, отправив сообщения SQS (используя boto3
), чтобы приложение Flask могло запустить долгосрочную задачу и в конечном итоге вернуть ответ HTTP 200, или вы можете добавить файл cron.yaml
для планирования периодических задач используя запись crontab.
Используя этот подход, вы удаляете Celery для управления задачами и полагаетесь на второй сервер Flask, которым вы управляете через SQS, или с файлом cron.yaml
, как cron.yaml
ниже.
Конфигурация WSGI
Я использовал инструмент awsebcli
для создания своей рабочей среды с именем "sqs-worker", например, eb create -t worker sqs-worker
. Затем мне нужно было настроить WSGIPath
для новой среды, поэтому я запустил eb config sqs-worker
. Я просто использовал имя моего файла application.py
, application.py
.
aws:elasticbeanstalk:container:python:
NumProcesses: '1'
NumThreads: '15'
StaticFiles: /static/=static/
WSGIPath: application.py
Рабочий план
Вот структура проекта для моего работника. Я держал это в отдельном репозитории Git от моего веб-сервера Django, который работал в отдельной среде.
worker/
├── .ebextensions
│ └── 01_logging.config
├── .elasticbeanstalk/...
├── venv/...
├── .gitignore
├── application.py
├── cron.yaml
├── requirements.txt
└── tasks.py
.ebextensions
.ebextensions
содержит дополнительную конфигурацию для среды Amazon AWS AMI Linux, которая является отдельной задачей для вашего приложения Python. У меня есть один файл конфигурации для создания файла журнала для отладки 'flask.log . This config file also arranges for
. This config file also arranges for
включение flashk.log to be included in the log files collected by Amazon so that you'll see it whenever you run
eb logs из командной строки.
commands:
00_create_dir:
command: mkdir -p /var/log/app-logs
01_change_permissions:
command: chmod g+s /var/log/app-logs
02_change_owner:
command: chown wsgi:wsgi /var/log/app-logs
files:
"/opt/elasticbeanstalk/tasks/taillogs.d/flask.conf":
mode: "000755"
owner: root
group: root
content: |
/var/log/app-logs/flask.log
"/opt/python/log/flask.log" :
mode: "000666"
owner: ec2-user
group: ec2-user
content: |
# flask log file
Разные предметы в работнике
.elasticbeanstalk
был создан инструментом awsebcli
, который, я думаю, выходит за рамки этого вопроса.
venv
- это виртуальная среда для Python, и он был создан python3 -m venv venv
. Виртуальную среду можно запустить, запустив source venv/bin/activate
. Затем пакеты можно установить в виртуальную среду, как обычно, с помощью pip, pip install package
, а затем pip install package
requirements.txt
можно сгенерировать как pip freeze > requirements.txt
.
Файл .gitignore
сообщает программе git, что игнорировать. Так как инструмент awsebcli
использует awsebcli
с awsebcli
git, этот файл, вероятно, будет вам полезен. Последний раздел, касающийся "Elastic Beanstalk Files", был автоматически добавлен awsebcli
.
# .gitignore
__pycache__
.pytest_cache
.vscode
db.sqlite3
venv
chromedriver
# Elastic Beanstalk Files
.elasticbeanstalk/*
!.elasticbeanstalk/*.cfg.yml
!.elasticbeanstalk/*.global.yml
Применение колбы
Я обнаружил, что мне нужно дать имя моему файлу application.py
Flask application.py
, и что мне нужно было дать имя моему приложению объекта application
Flask. Здесь tasks.py
- это простой скрипт на Python с несколькими определенными функциями очистки. Обратите внимание, что мы /opt/python/log/flask.log
в /opt/python/log/flask.log
. Я создаю flask.log
в конфигурационном файле .ebextension
, так что позаботьтесь об этом позже. Я перечислил несколько конечных точек, чтобы проиллюстрировать, что вы можете использовать разные конечные точки в вашем файле cron.yaml
.
# application.py
import datetime
from flask import Flask, Response
import logging
import tasks
application = Flask(__name__)
logging.basicConfig(filename='/opt/python/log/flask.log', level=logging.INFO)
def get_timestamp():
date_fmt = '%Y/%m/%d %H:%M:%S'
date_now = datetime.datetime.now()
date_str = datetime.datetime.strftime(date_now, date_fmt)
return date_str
@application.route('/worker/scrape/', methods = ['POST'])
def scrape():
application.logger.info(get_timestamp())
data = tasks.scrape()
application.logger.info(data)
return Response(status="200")
@application.route('/worker/archives/', methods = ['POST'])
def scrape_archives():
application.logger.info(get_timestamp())
data = tasks.scrape_archives()
application.logger.info(data)
return Response(status="200")
@application.route('/worker/posts/', methods = ['POST'])
def scrape_posts():
application.logger.info(get_timestamp())
data = tasks.scrape_posts()
application.logger.info(data)
return Response(status="200")
Cron
Вот мой файл cron.yaml
. Я использую нотацию crontab для запуска всего каждые три минуты, одна задача в минуту.
# cron.yaml
version: 1
cron:
- name: "scrape"
url: "/worker/scrape/"
schedule: "0-59/3 * * * *"
- name: "scrape-archives"
url: "/worker/archives/"
schedule: "1-59/3 * * * *"
- name: "scrape-posts"
url: "/worker/posts/"
schedule: "2-59/3 * * * *"
Полезные ссылки
Платформа Python в AWS: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create-deploy-python-container.html
Развертывание Flask на AWS: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create-deploy-python-flask.html
Развертывание Django в AWS: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create-deploy-python-django.html.
Обзор рабочей среды: https://colintoh.com/blog/configure-worker-for-aws-elastic-beanstalk
Колба AWS Gotchas: http://blog.uptill3.com/2012/08/25/python-on-elastic-beanstalk.html
Видео от AWS: https://medium.com/aws-activate-startup-blog/a-sample-app-for-startups-2f8483c62b68