使用 Celery 和 Redis 实现 SSL 连接

首先

Celery是用于在Python中处理队列任务的框架。
虽然Celery可以使用Redis作为Broker,但在使用Azure的Azure Redis Cache时,遇到了使用SSL的问题,因此在这里记录下使用方法。

环境

    • Python: 3.5.2

 

    • Celery: 4.0.0

 

    Redis: Azure Redis Cache を利用。Standardプランのため、Virtual Network内に配置することができず、Global IPに紐付いたHostに対してアクセスするので、セキュリティのためSSLの利用が必要となる。Premium プランだと、Private Subnet の中に配置することが可能。Premium Azure Redis Cache の Virtual Network のサポートを構成する方法

我們假設使用Flask作為Web應用程序,但我認為在其他環境中也是一樣的。

要使用SSL

根据Celery 4.0(latentcall)的最新消息,从版本4.0开始,Celery可以在Redis中使用SSL连接。

据说可以通过设置broker_use_ssl来使用它,但对于Redis而言,即使盲目配置此信息也无法正常工作。

Error while reading from socket: (104, 'Connection reset by peer')

遇到这个错误会导致困扰。这个错误是由于在Celery内部与Redis的连接中,使用了redis.connection.Connection而不是redis.connection.SSLConnection所导致的。

修复Redis的SSL支持。如果不参考此拉取请求进行配置,则无法使用SSL。

from celery import Celery
from redis.connection import SSLConnection
from .config import broker_use_ssl


def make_celery(app):
    celery = Celery(app.import_name, backend=app.config['CELERY_BACKEND'],
                    broker=app.config['CELERY_BROKER_URL'])
    celery.conf.update(app.config)
    celery.conf.update(broker_use_ssl=broker_use_ssl)

    # URL: https://github.com/celery/kombu/pull/634
    if celery.conf.broker_use_ssl:
        celery.backend.connparams.update(celery.conf.broker_use_ssl) # <- ここ
        celery.backend.connparams['connection_class'] = SSLConnection # <- ここ

    TaskBase = celery.Task

    class ContextTask(TaskBase):
        abstract = True

        def __call__(self, *args, **kwargs):
            with app.app_context():
                return TaskBase.__call__(self, *args, **kwargs)

    celery.Task = ContextTask
    return celery

通过make_celery的参数传递的app是Flask应用程序的上下文。
在设置broker_use_ssl之后,需要设置celery.backend.connparams[‘connection_class’] = SSLConnection。

另外,在文件中指出,可以将broker_use_ssl设置为True或字典,但是即使将其设置为True,它也不起作用。您需要设置一个字典。与Ruby不同的是,如果字典为空,它会被判定为False。

broker_use_ssl = {'ssl_cert_reqs': ssl.CERT_NONE}

我认为留作备用是个好主意。

密码

在中国的当地语言中重新表述以下内容,只需提供一个选项:
在Celery中,设置密码。

CELERY_BROKER_URL = "redis://:password@hostname:port/db_number"

必须以这种形式进行设置。由于我浪费了一些关于HTTP之类的知识,所以我开始怀疑是否可以在URI中包含密码。但是当我查看内部实现时,发现URI会被正确解析。

最后

芹菜的内部实现出乎意料地复杂且难以阅读。
此外,Azure的文档中有关使用Python在Azure Redis Cache中的方法。

由于一些Redis客户端不支持SSL,所以新的Azure Redis Cache实例默认情况下禁用了非SSL端口。在撰写本文时,redis-py客户端不支持SSL。

根据提交日志,redis-py在2014年就已经支持SSL。希望更新旧有的描述,以免造成困扰。

请参考此链接

github – Fix Redis SSL support
What’s new in Celery 4.0 (latentcall)

bannerAds