Celery, Flower 의 서버설정 과정을 정리해 보았습니다.


Content


Uvicorn

Running with Gunicorn

Django 공식문서 에서도 서버 실행을 위한 미들웨어로 Uvicorn 를 언급하고 있습니다. 아래의 명령어 하나만 실행하면 127.0.0.1:8000 에서 실행되는 내용을 로그에서 확인 가능합니다.

$ gunicorn mysite.asgi:application -w 2 -k uvicorn.workers.UvicornWorker

gunicorn service

위 스크립트를 자동으로 실행하도록 service deamon 을 등록 합니다.

  1. User 는 스크립트를 실행하는 우분투 User 의 이름을 입력합니다.
  2. Group 은 nginx.conf 의 user 이름을 입력 합니다.
$ sudo vi /etc/systemd/system/gunicorn.service
[Unit]
Description=HomePage
After=network.target

[Service]
User=USERNAME
Group=www-data
WorkingDirectory=/home/USERNAME/Source
ExecStart=/home/USERNAME/Python/venv/bin/gunicorn myproject.asgi:application -k uvicorn.workers.UvicornWorker

[Install]
WantedBy=multi-user.target

daemon service

  1. daemon 과 연결작업을 먼저 한 뒤
  2. System 자동실행 등록 절차를 진행 합니다
  3. 재설정 하는 경우, 서비스를 종료를 한 뒤 새로 연결작업을 진행 해야 합니다.
$ sudo systemctl -h
$ sudo systemctl enable gunicorn
  Created symlink 
  /etc/systemd/system/multi-user.target.wants/gunicorn.service
  → /etc/systemd/system/gunicorn.service.

$ sudo systemctl start gunicorn   # 서비스 시작
$ sudo systemctl status gunicorn  # 상태확인
$ sudo systemctl -f stop gunicorn # 멈춤 (재부팅시 재실행 된다)
$ sudo systemctl disable gunicorn # 재부팅시 실행 안함


Nginx

Install

Nginx 우분투 설치가이드 에는 ubuntu 20.04 설치 방법만 기술되어 있습니다. 이는 앞의 내용을 참고 하여 우분투 버젼에 맞는 내용을 다운로드 합니다.

파일의 구성

NGINX 의 설정 내용은 크게 2가지로 나눠 볼 수 있습니다.

  1. nginx.conf Nginx 기본설정
  2. default.conf 또는 default 의 서비스 설정

nginx.conf

user 이름은 service 등록에 사용 합니다. 주의할 내용은 user 이름은 우분투 사용자 이름과 별개의 데이터로써 관리 됩니다.

$ cat vi /etc/nginx/nginx.conf

user www-data;
worker_processes auto;
include /etc/nginx/conf.d/*.conf;

default.conf (default)

Django 에서 설정한 Static 과 Media 폴더에 대한 내용은 Nginx 를 활용하여 연결 합니다. 추가로 Axios 에서 Post 호출을 사용하는 경우에는 앞의 내용을 참고 합니다.

server {
  listen       80;
  server_name  django;
  charset      utf-8;
  location / {
    proxy_pass http://127.0.0.1:8000;
  }
  location /static/ {
    autoindex on;
    alias /home/user/django/staticfiles/;
    expires 1d;
  }
  location /media/ {
    alias /home/user/django/media/;
    expires 1d;
  } 
}

Reload

변경된 설정내용이 있으면 서버를 재실행 합니다.

$ nginx -s [ stop | quit | reopen | reload ]

무료 SSL 설치 및 자동 업데이트 설정

Update: Using Free Let’s Encrypt SSL/TLS Certificates with NGINX


Celery

Daemonizing 은 여러가지 방법이 있습니다. 이번 페이지 에서는 위 Uvicorn 에서 살펴본 내용과 같이 systemd 에서 등록하는 방법을 정리해 보겠습니다.

Setting Files

Celery 는 celery.service 와 celerybeat.service 2개의 서비스를 필요로 합니다. 2개의 서비스 파일은 공식문서의 내용을 그대로 사용하면 됩니다. 사용자 변수 내용은 /etc/conf.d/celery 파일을 호출하는 방식으로 운영 됩니다.

  1. /etc/systemd/system/celery.service
  2. /etc/systemd/system/celerybeat.service
  3. /etc/conf.d/celery

Celery Worker

공식문서를 참고하여 초간단 버젼으로 서비스 파일을 작성해 보겠습니다. 기본 골격은 앞의 gunicorn 데몬 파일을 재활용 하였고 추가적인 옵션들만 덧붙여 보았습니다.

2022-04추가 이벤트 로그 확인을 용이하도록 -E 옵션을 추가 합니다.

$ sudo vi /etc/systemd/system/celery.service

[Unit]
Description=MarketSearch
After=network.target

[Service]
Type=forking
User=USERNAME
Group=www-data
WorkingDirectory=/home/USERNAME/Source
ExecStart=/home/USERNAME/Python/venv/bin/celery -A server worker -l info -E
Restart=always

[Install]
WantedBy=multi-user.target

Celery Beat

$ sudo vi /etc/systemd/system/celerybeat.service

[Unit]
Description=DjangoSite
After=network.target

[Service]
Type=simple
User=USERNAME
Group=www-data
WorkingDirectory=/home/USERNAME/Source
ExecStart=/home/USERNAME/venv/bin/celery -A server beat -l info
Restart=always
StartLimitBurst=0

[Install]
WantedBy=multi-user.target

SystemCTL

앞에 작성한 2개의 파일을 시스템 파일로 등록을 한 뒤 재부팅과 함께 정상작동 하는지 확인 합니다.

$ sudo systemctl enable celery.service                 
  Created symlink 
  /etc/systemd/system/multi-user.target.wants/celery.service
  → /etc/systemd/system/celery.service.

$ sudo systemctl enable celerybeat.service
  Created symlink 
  /etc/systemd/system/multi-user.target.wants/celerybeat.service 
  → /etc/systemd/system/celerybeat.service.

내용의 추가

2020-10-22 systemd[1]: celerybeat.service: Start request repeated too quickly.

재부팅한 경우 위 오류가 나타나 제대로 실행되지 않는 경우가 빈번하게 발생하였습니다. 동일한 문제가 발생하는 경우에는 아래의 명령을 추가 적용 합니다.

$ systemctl show -p FragmentPath celerybeat.service
  FragmentPath=/usr/lib/systemd/system/celerybeat.service
$ systemctl daemon-reload

Celery Beat 의 log 를 확인해보니, status 는 정상작동을 했는데, log 에서 Celery beat not starting EOFError('Ran out of input') 오류를 계속 반복해서 출려하고 있었습니다. Nginx 설정값을 변경해준 뒤 링크 내용을 적용하니 해결 되었습니다.


Flower

Nginx for Flower

Flower 는 Django 와 별개의포트에서 동작 합니다. Nginx 에서 외부 경로를 통해 연결할 수 있도록 아래 내용을 추가한 뒤 Nginx 를 재실행 합니다. Stackoverflow 자료출처

location ~ ^/flower/? {
  rewrite ^/flower/?(.*)$ /$1 break;

  sub_filter '="/' '="/flower/';
  sub_filter_last_modified on;
  sub_filter_once off;

  # proxy_pass http://unix:/tmp/flower.sock:/;
  proxy_pass http://localhost:5555;
  proxy_redirect off;
  proxy_set_header Host $host;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
  proxy_http_version 1.1;
}

flower.service

Flower 공식문서 는 Celery 동작 내용을 모니터링 GUI를 생성하는 모듈 입니다. daemon 등록예제 를 참고하여 본인의 시스템에 맞게 내용을 보완 합니다.

외부접속시 보안 을 추가할 수 있습니다

$ sudo vi /etc/systemd/system/flower.service

[Unit]
Description=Flower Celery Service

[Service]
User=USERNAME
Group=www-data
WorkingDirectory=/home/USERNAME/Source
Environment=/home/USERNAME/Python/venv/bin/celery flower -A server --broker=redis://localhost:6379/0 --basic_auth=user1:password1,user2:password2
Restart=on-failure
Type=simple

[Install]
WantedBy=multi-user.target

그리고 서비스에 등록 합니다.

$ sudo systemctl enable flower.service        
  Created symlink 
  /etc/systemd/system/multi-user.target.wants/flower.service
  → /etc/systemd/system/flower.service.

flower service 내용추가

위 내용대로 적용하면 Localhost 에서는 잘 동작을 하는 모습을 보였지만, Server 에서는 Flower 의 status 와 연결이 되지않아서 동작의 상세 내용을 확인할 수 없었습니다.

임시 방법으로 아래의 명령을 사용하면 터미널에서 직접 이벤트 실행 내용을 확인할 수 있습니다.

$ celery -A server events --dump

flower 가 localhost 에서 잘 작동했지만, Django 와 flower 가 Nginx 에 의해 다른 경로로 동작 하는 경우 Celery task 를 찾지 못해서 status 가 online 으로 연결되지 않는 문제가 있었습니다.

원인은 flower 파이썬 모듈의 flower.js 파일에서 Nginx 에서 변경된 flower 경로를 찾지 못해서 발생한 것이었습니다. 이를 해결하기 위해서 우선 서버에서 celery 와 celerybeat 시스템 상태가 안정적으로 동작하는 것을 확인 합니다.

$ find ./ -name "flower.js"
 ./venv/lib/python3.8/site-packages/flower/static/js/flower.js

그리고 flower.js 파일의 url_prefix() 함수에서 경로명을 Nginx 의 설정한 경로와 일치 시켜줌으로써 해결 가능했습니다.

// python3.8/site-packages/flower/static/js/flower.js
function   {
  var url_prefix = $('#url_prefix').val();
  if (url_prefix) {
    if (url_prefix.startsWith('/')) {
      return '/flower' + url_prefix;
    } else {
      return '/flower' + '/' + url_prefix;
    }
  }
  return '/flower';
}


Supervisor

추가적으로 터미널에서 이벤트 상태를 확인할 수 있는 모듈 입니다. Nginx 처럼 별도의 모듈로써 동작을 하기 때문에 celery 와 celerybeat 설정 내용값을 모두추가해야 합니다. 설정예제 를 참고 하면 됩니다.


참고사이트