├── .dockerignore ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── bin └── flower.sh ├── celeryconfig.py ├── docker-compose.yml └── flowerconfig.py /.dockerignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .git* 3 | LICENSE 4 | README.md 5 | *.iml 6 | docker-compose.yml 7 | __pycache__ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | 56 | .idea 57 | *.iml 58 | *~ 59 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.5.1-alpine 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | ENV ETCDCTL_VERSION v2.2.5 5 | ENV DUMB_INIT_VERSION 1.0.1 6 | 7 | RUN apk add --no-cache --update \ 8 | openssl \ 9 | curl \ 10 | 11 | # Etcdctl 12 | && curl -L https://github.com/coreos/etcd/releases/download/$ETCDCTL_VERSION/etcd-$ETCDCTL_VERSION-linux-amd64.tar.gz -o /tmp/etcd-$ETCDCTL_VERSION-linux-amd64.tar.gz \ 13 | && cd /tmp && gzip -dc etcd-$ETCDCTL_VERSION-linux-amd64.tar.gz | tar -xof - \ 14 | && cp -f /tmp/etcd-$ETCDCTL_VERSION-linux-amd64/etcdctl /usr/local/bin \ 15 | 16 | # Dumb Init 17 | && wget -O /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_amd64 \ 18 | && chmod +x /usr/bin/dumb-init \ 19 | 20 | # Cleanup 21 | && rm -rf /tmp/* 22 | 23 | RUN pip3 install --ignore-installed --no-cache-dir flower==0.9.0 \ 24 | # Cleanup (Remove all tests folder and python compiled files) 25 | && find /usr/local \ 26 | \( -type d -a -name test -o -name tests \) -exec echo rm -rf '{}' + \ 27 | -o \( -type f -a -name '*.pyc' -o -name '*.pyo' \) -exec echo rm -f '{}' + \ 28 | && rm -rf /usr/src/python ~/.cache 29 | 30 | ADD celeryconfig.py flowerconfig.py /opt/celery-flower/ 31 | ADD bin/flower.sh /opt/celery-flower/bin/ 32 | RUN chmod +x /opt/celery-flower/bin/flower.sh 33 | 34 | WORKDIR /opt/celery-flower 35 | 36 | EXPOSE 5555 37 | 38 | CMD ["/usr/bin/dumb-init", "/opt/celery-flower/bin/flower.sh"] 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Totem 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # celery-flower-docker 2 | Docker container for monitoring celery 3 | 4 | ## Running with docker 5 | 6 | In order to run flower using docker , run 7 | command: 8 | 9 | ``` 10 | sudo docker run -it --rm --name flower -p 5555:5555 totem/celery-flower-docker 11 | ``` 12 | 13 | ## Access Flower 14 | 15 | To access flower go to url: [http://172.17.42.1:5555](http://172.17.42.1:5555). 16 | The default credentials for the flower instance is username:root password:changeit. 17 | (It is highly recommended to change the default credentials. See run configuration.) 18 | 19 | If your are using dynamic port mapping using (-P), inspect the container to determine the mapped 20 | port for 5555. 21 | 22 | ## Run Configuration (Environment Variables) 23 | | Env Variable | Description | Default Value (Docker)| 24 | | ------------ | ----------- |--------------------- | 25 | | FLOWER_PORT | Port to be used by flower | 5555 | 26 | | AMQP_USERNAME | Rabbitmq broker username | guest | 27 | | AMQP_PASSWORD | Rabbitmq broker password | guest | 28 | | AMQP_HOST | Rabbitmq host | 172.17.42.1 | 29 | | AMQP_PORT | Rabbitmq port | 5672 | 30 | | AMQP_ADMIN_USERNAME | Rabbitmq admin username | guest | 31 | | AMQP_ADMIN_PASSWORD | Rabbitmq admin password | guest | 32 | | AMQP_ADMIN_HOST | Rabbitmq admin host | 172.17.42.1 | 33 | | AMQP_ADMIN_PORT | Rabbitmq admin port | 15672 | 34 | | FLOWER_MAX_TASKS | Max tasks to be stored in memory. | 3600 | 35 | | FLOWER_BASIC_AUTH | Authentication for flower (username:passowrd) | root:changeit | 36 | -------------------------------------------------------------------------------- /bin/flower.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | # Defaults 4 | export LOG_LEVEL="${LOG_LEVEL:-info}" 5 | export HOST_IP="${HOST_IP:-$(/sbin/ip route|awk '/default/ { print $3 }')}" 6 | export AMQP_HOST="${AMQP_HOST:-$HOST_IP}" 7 | export AMQP_ADMIN_HOST="${AMQP_ADMIN_HOST:-$HOST_IP}" 8 | export DISCOVER_RABBITMQ="${DISCOVER_RABBITMQ:-false}" 9 | export ETCD_HOST="${ETCD_HOST:-$HOST_IP}" 10 | export ETCD_PORT="${ETCD_PORT:-4001}" 11 | export ETCD_URL="${ETCD_URL:-http://$ETCD_HOST:$ETCD_PORT}" 12 | export ETCDCTL="${ETCDCTL:-etcdctl --peers $ETCD_URL}" 13 | export ETCD_TOTEM_BASE="${ETCD_TOTEM_BASE:-/totem}" 14 | 15 | if [ "$DISCOVER_RABBITMQ" == "true" ]; then 16 | until $ETCDCTL cluster-health; do 17 | >&2 echo "Etcdctl cluster not healthy - sleeping" 18 | sleep 10 19 | done 20 | 21 | export AMQP_HOST="$($ETCDCTL ls $ETCD_TOTEM_BASE/rabbitmq/nodes | xargs -n 1 $ETCDCTL get | xargs echo -n | tr ' ' ',')" 22 | until [ ! -z "$AMQP_HOST" ]; do 23 | >&2 echo "Rabbitmq could not be discovered - sleeping" 24 | sleep 10 25 | export AMQP_HOST="$($ETCDCTL ls $ETCD_TOTEM_BASE/rabbitmq/nodes | xargs -n 1 $ETCDCTL get | xargs echo -n | tr ' ' ',')" 26 | done 27 | fi 28 | 29 | /usr/local/bin/celery --loglevel="$LOG_LEVEL" flower 30 | -------------------------------------------------------------------------------- /celeryconfig.py: -------------------------------------------------------------------------------- 1 | import os 2 | AMQP_USERNAME = os.getenv('AMQP_USERNAME', 'guest') 3 | AMQP_PASSWORD = os.getenv('AMQP_PASSWORD', 'guest') 4 | AMQP_HOST = os.getenv('AMQP_HOST', '172.17.42.1') 5 | AMQP_PORT = int(os.getenv('AMQP_PORT', '5672')) 6 | 7 | DEFAULT_BROKER_URL = [ 8 | 'amqp://{}:{}@{}:{}'.format( 9 | AMQP_USERNAME, AMQP_PASSWORD, host.strip(), AMQP_PORT 10 | ) for host in AMQP_HOST.split(',') if host.strip() 11 | ] 12 | 13 | BROKER_URL = os.getenv('BROKER_URL', DEFAULT_BROKER_URL) 14 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | networks: 4 | local: 5 | driver: 'bridge' 6 | 7 | services: 8 | flower: 9 | build: . 10 | networks: 11 | local: 12 | aliases: 13 | - flower.local 14 | environment: 15 | ETCD_HOST: 'etcd.local' 16 | AMQP_HOST: 'rabbitmq.local' 17 | AMQP_ADMIN_HOST: 'rabbitmq.local' 18 | DISCOVER_RABBITMQ: 'false' 19 | ports: 20 | - 5555 21 | 22 | depends_on: 23 | - etcd 24 | - rabbitmq 25 | restart: always 26 | volumes: 27 | - ".:/opt/celery-flower" 28 | 29 | rabbitmq: 30 | image: 'rabbitmq:3.6' 31 | networks: 32 | local: 33 | aliases: 34 | - rabbitmq.local 35 | 36 | etcd: 37 | image: 'quay.io/coreos/etcd' 38 | command: [ 39 | '-name', 'etcd0', 40 | '-advertise-client-urls','http://etcd.local:2379,http://etcd.local:4001', 41 | '-listen-client-urls', 'http://0.0.0.0:2379,http://0.0.0.0:4001', 42 | '-initial-advertise-peer-urls', 'http://etcd.local:2380', 43 | '-listen-peer-urls', 'http://0.0.0.0:2380', 44 | '-initial-cluster-token', 'etcd-cluster-1', 45 | '-initial-cluster', 'etcd0=http://etcd.local:2380', 46 | '-initial-cluster-state', 'new', 47 | ] 48 | 49 | networks: 50 | local: 51 | aliases: 52 | - etcd.local 53 | volumes: 54 | - /usr/share/ca-certificates/:/etc/ssl/certs -------------------------------------------------------------------------------- /flowerconfig.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | AMPQ_ADMIN_USERNAME = os.getenv('AMQP_ADMIN_USERNAME', 'guest') 4 | AMPQ_ADMIN_PASSWORD = os.getenv('AMQP_ADMIN_PASSWORD', 'guest') 5 | AMQP_ADMIN_HOST = os.getenv('AMQP_ADMIN_HOST', '172.17.42.1') 6 | AMQP_ADMIN_PORT = int(os.getenv('AMQP_ADMIN_PORT', '15672')) 7 | 8 | DEFAULT_BROKER_API = 'http://%s:%s@%s:%d/api/' \ 9 | % (AMPQ_ADMIN_USERNAME, AMPQ_ADMIN_PASSWORD, 10 | AMQP_ADMIN_HOST, AMQP_ADMIN_PORT) 11 | USERNAME = os.getenv('USERNAME', 'root') 12 | PASSWORD = os.getenv('PASSWORD', 'changeit') 13 | 14 | port = int(os.getenv('FLOWER_PORT', '5555')) 15 | broker_api = os.getenv('FLOWER_BROKER_API', DEFAULT_BROKER_API) 16 | max_tasks = int(os.getenv('FLOWER_MAX_TASKS', '3600')) 17 | basic_auth = [os.getenv('FLOWER_BASIC_AUTH', '%s:%s' 18 | % (USERNAME, PASSWORD))] 19 | --------------------------------------------------------------------------------