Проблемы с разрешением с Django / Сельдерей на Elastic Beanstalk - PullRequest
0 голосов
/ 23 мая 2018

Мое приложение (clads) работает на Django и использует Celery для временных и асинхронных задач.К сожалению, я не могу понять некоторые проблемы с разрешениями, которые мешают процессам Celery записывать в журналы приложения Django или манипулировать файлами, созданными приложением Django.Приложение Django запускается в процессе wsgi, и у меня есть несколько файлов конфигурации, которые устанавливают каталог журнала приложения, чтобы процесс wsgi мог писать в него (см. Ниже).

Однако кажется, что процессы сельдерея выполняются от имени другого пользователя, у которого нет разрешения на запись в эти файлы (что он автоматически пытается сделать, когда видит конфигурацию файла журнала - также ниже). Примечание Iпытался изменить это, чтобы работать как WSGI, но не работает).Похоже, что та же самая проблема с разрешениями не позволяет процессу Celery манипулировать временными файлами, созданными приложением Django - требование проекта.

По общему признанию я очень ржавый на операционных системах типа Unix, поэтому я уверен, что упускаю какую-то простую вещь.Я искал этот сайт и другие в течение нескольких дней, и хотя я нашел много постов, которые приблизили меня к этой проблеме, я все еще не могу решить ее.Я подозреваю, что могут быть некоторые дополнительные команды, которые мне нужны в моей конфигурации, чтобы установить разрешения или запустить Celery под другим пользователем.Любая помощь будет принята с благодарностью.Конфигурация проекта и соответствующие файлы кода приведены ниже.Большинство файлов конфигурации были собраны вместе из информации, найденной на этом и других сайтах - извините за то, что не разместили, но не держали достаточно близко записей, чтобы точно знать, откуда они пришли.

Журнальные и Celery части settings.py

#log settings
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
    'verbose': {
        'format': '%(asctime)s - %(levelname)s - %(module)s.%(fileName)s.%(funcName)s %(processName)d %(threadName)d: %(message)s',
    },
    'simple': {
        'format': '%(asctime)s - %(levelname)s: %(message)s'
    },
},
'handlers' : {
    'django_log_file': {
        'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
        'class': 'logging.FileHandler',
        'filename': os.environ.get('DJANGO_LOG_FILE'),
        'formatter': 'verbose',
    },
    'app_log_file': {
        'level': os.getenv('CLADS_LOG_LEVEL', 'INFO'),
        'class': 'logging.FileHandler',
        'filename': os.environ.get('CLADS_LOG_FILE'),
        'formatter': 'verbose',
    },
},
'loggers': {
    'django': {
        'handlers': ['django_log_file'],
        'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
        'propagate': True,
    },
    'clads': {
        'handlers': ['app_log_file'],
        'level': os.getenv('CLADS_LOG_LEVEL', 'INFO'),
        'propagate': True,
    },
},
}

WSGI_APPLICATION = 'clads.wsgi.application'

# celery settings
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'

CELERY_RESULT_BACKEND = 'djcelery.backends.database:DatabaseBackend'
CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'
CELERY_SEND_EVENTS = False

CELERY_BROKER_URL = os.environ.get('BROKER_URL')

tasks.py выдержки LOGGER = logging.getLogger ('clads.pit')

@shared_task(name="archive_pit_file")
def archive_pit_file(tfile_name):
    LOGGER.debug('archive_date_file called for ' + tfile_name)

    LOGGER.debug('connecting to S3 ...')
    s3 = boto3.client('s3')

    file_fname = os.path.join(settings.TEMP_FOLDER, tfile_name)
    LOGGER.debug('reading temp file from ' + file_fname)
    s3.upload_file(file_fname, settings.S3_ARCHIVE, tfile_name)

    LOGGER.debug('cleaning up temp files ...')

    #THIS LINE CAUSES PROBLEMS BECAUSE THE CELERY PROCESS DOES'T HAVE 
    #PERMISSION TO REMOVE TEH WSGI OWNED FILE 
    os.remove(file_fname)

logging.config

commands:
  01_change_permissions:
      command: chmod g+s /opt/python/log
  02_change_owner:
      command: chown root:wsgi /opt/python/log

99_celery.config

container_commands:  
  04_celery_tasks:
    command: "cat .ebextensions/files/celery_configuration.txt > /opt/elasticbeanstalk/hooks/appdeploy/post/run_supervised_celeryd.sh && chmod 744 /opt/elasticbeanstalk/hooks/appdeploy/post/run_supervised_celeryd.sh"
    leader_only: true
 05_celery_tasks_run:
   command: "/opt/elasticbeanstalk/hooks/appdeploy/post/run_supervised_celeryd.sh"
   leader_only: true

celery_configuration.txt

#!/usr/bin/env bash

# Get django environment variables
celeryenv=`cat /opt/python/current/env | tr '\n' ',' | sed 's/%/%%/g' | 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-worker]  
; Set full path to celery program if using virtualenv
command=/opt/python/run/venv/bin/celery worker -A clads -b <broker_url> --loglevel=INFO --without-gossip --without-mingle --without-heartbeat

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

[program:celeryd-beat]
; Set full path to celery program if using virtualenv
command=/opt/python/run/venv/bin/celery beat -A clads -b <broker_url> --loglevel=INFO --workdir=/tmp

directory=/opt/python/current/app  
user=nobody  
numprocs=1  
stdout_logfile=/var/log/celery-beat.log  
stderr_logfile=/var/log/celery-beat.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-worker  
supervisorctl -c /opt/python/etc/supervisord.conf restart celeryd-beat  

1 Ответ

0 голосов
/ 07 июня 2018

Я не смог точно выяснить проблему с разрешениями, но нашел обходной путь, который мог бы помочь другим.Я удалил конфигурации FileHandler в настройках журнала и заменил их на StreamHandler.Это позволило обойти проблему с разрешениями, поскольку процессам Celery не нужно было пытаться получить доступ к файлу журнала, принадлежащему пользователю wsgi.

Сообщения журнала от веб-приложения попадают в журнал ошибок httpd - не идеально, но, по крайней мере, я могу их найти, и они также доступны через консоль эластичного бобового стебля - а журналы Celery записываются в celery-worker.log и celery-beat.log в / var / log.Я не могу получить к ним доступ через консоль, но могу получить к ним доступ, войдя непосредственно в экземпляр.Это также не идеально, так как эти журналы не будут повернуты и будут потеряны, если экземпляр будет удален, но, по крайней мере, он заставил меня работать в данный момент.

Вот измененные настройки журнала, которые заставили его работать так:путь:

#log settings
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(asctime)s - %(levelname)s - %(module)s.%(filename)s.%(funcName)s %(processName)s %(threadName)s: %(message)s',
        },
        'simple': {
            'format': '%(asctime)s - %(levelname)s: %(message)s'
        },
    },
    'handlers' : {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
        }
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
            'propagate': True,
        },
        'clads': {
            'handlers': ['console'],
            'level': os.getenv('CLADS_LOG_LEVEL', 'INFO'),
            'propagate': True,
        },
    },
}
...