couldn't start Celery with docker-compose

2019-07-09 23:58发布

问题:

I have Flask app with Celery worker and Redis and it's working normally as expected when running on local machine. Then I tried to Dockerize the application. When I trying to build/start the services ( ie, flask app, Celery, and Redis) using sudo docker-compose up all services are running except Celery and showing an error as

ImportError: No module named 'my_celery'

But, the same code working in local machine without any errors. Can any one suggest the solution?

Dockerfile

FROM python:3.5-slim
WORKDIR celery_sample
ADD . /celery_sample
RUN pip install -r requirements.txt
EXPOSE 8000

docker-compose.yml

version: "3"
services:

  web:
    build:
      context: .
      dockerfile: Dockerfile
    command: "python my_celery.py"
    ports:
      - "8000:8000"
    networks:
      - webnet
    volumes:
      - .:/celery_sample

  redis:
    image: redis
    networks:
      - webnet


  celery:
    image: celery:3.1.25
    command: "celery worker -A my_celery -l INFO"
    volumes:
      - .:/celery_sample
    networks:
      - webnet

networks:
  webnet:

requirements.txt

flask==0.10
redis
requests==2.11.1
celery==3.1.25

my_celery.py ( kindly ignore the logic)

from flask import Flask
from celery import Celery
flask_app = Flask(__name__)
celery_app = Celery('my_celery')
celery_app.config_from_object('celeryconfig')



@celery_app.task
def add_celery():
    return str(int(10)+int(40))


@flask_app.route('/')
def index():
    return "Index Page"

@flask_app.route('/add')
def add_api():
    add_celery.delay()
    return "Added to Queue"

if __name__ == '__main__':
    flask_app.debug = True
    flask_app.run(host='0.0.0.0', port=8000)

celeryconfig.py

## Broker settings.
BROKER_URL = 'redis://localhost:6379/0'    
## Using the database to store task state and results.
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'

回答1:

First of all the celery image is deprecated in favour of standard python image more info here.

WORKDIR sets the working directory for all the command after it is defined in the Dockerfile, which means the command which you are try to run will run from that directory. Docker image for celery sets the working directory to /home/user.

Since your code is mounted on /celery_smaple and the working directory is /home/user, Celery is not able to find your python module.

One alternative is to cd into the mounted directory and execute the command:

celery:
    image: celery:3.1.25
    command: "cd /celery_sample && celery worker -A my_celery -l INFO"
    volumes:
      - .:/celery_sample
    networks:
      - webnet

notice the command

And another one is to create your own image with WORKDIR set to /celery_sample eg:

FROM python:3.5
RUN pip install celery==3.1.25
WORKDIR /celery_sample

after building you own image you can use the compose file by changing the image of celery service

Edit

You need to link the services to one another in order to communicate:

version: "3"
services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    command: "python my_celery.py"
    ports:
      - "8000:8000"
    networks:
      - webnet
    volumes:
      - .:/celery_sample
    links:
      - redis

  redis:
    image: redis
    networks:
      - webnet

  celery:
    image: celery:3.1.25
    command: "celery worker -A my_celery -l INFO"
    volumes:
      - .:/home/user
    networks:
      - webnet
    links:
      - redis

networks:
  webnet:

and your configuration file should be:

## Broker settings.
BROKER_URL = 'redis://redis:6379/0'    
## Using the database to store task state and results.
CELERY_RESULT_BACKEND = 'redis://redis:6379/0'

once you have linked the services in compose file you can access the service by using the service name as the hostname.



回答2:

The simplest change you can make is to map the directory for celery image correctly in yaml

  celery:
    image: celery:3.1.25
    command: "celery worker -A my_celery -l INFO"
    volumes:
      - .:/home/user/
    networks:
      - webnet

Also as @vedarthk pointed, you should be using the official Python image for this instead of celery image