【问题标题】:How to deploy rabbitmq with flask and docker?如何用flask和docker部署rabbitmq?
【发布时间】:2019-09-30 06:49:23
【问题描述】:

我正在做一个应用程序,后部使用flask,前部使用angular,具有微服务架构。 对于部署,我使用的是 docker,现在的问题是服务之间的通信。我读过最好的选择 es rabbit-mqtt,但我还没有找到任何教程。

我没有多少时间,因为它是为了完成我的学位,所以我需要一个教程,让我能够快速创建服务之间的通信。

flask 不安分,我使用管理器创建 API-CRUD。

提前致谢

【问题讨论】:

    标签: python docker flask rabbitmq microservices


    【解决方案1】:

    我是这样做的:

    1. Flask 服务器
    from flask import Flask
    import pika
    import uuid
    import threading
    
    app = Flask(__name__)
    queue = {}
    
    
    class FibonacciRpcClient(object):
    
        def __init__(self):
            self.connection = pika.BlockingConnection(
                pika.ConnectionParameters(host='rabbit'))
    
            self.channel = self.connection.channel()
    
            result = self.channel.queue_declare('', exclusive=True)
            self.callback_queue = result.method.queue
    
            self.channel.basic_consume(
                queue=self.callback_queue,
                on_message_callback=self.on_response,
                auto_ack=True)
    
        def on_response(self, ch, method, props, body):
            if self.corr_id == props.correlation_id:
                self.response = body
    
        def call(self, n):
            self.response = None
            self.corr_id = str(uuid.uuid4())
            queue[self.corr_id] = None
            self.channel.basic_publish(
                exchange='',
                routing_key='rpc_queue',
                properties=pika.BasicProperties(
                    reply_to=self.callback_queue,
                    correlation_id=self.corr_id,
                ),
                body=str(n))
            while self.response is None:
                self.connection.process_data_events()
            queue[self.corr_id] = self.response
            print(self.response)
            return int(self.response)
    
    
    @app.route("/calculate/<payload>")
    def calculate(payload):
        n = int(payload)
        fibonacci_rpc = FibonacciRpcClient()
        threading.Thread(target=fibonacci_rpc.call, args=(n,)).start()
        return "sent " + payload
    
    
    @app.route("/results")
    def send_results():
        return str(queue.items())
    
    
    1. 工人
    import pika
    
    connection = pika.BlockingConnection(
        pika.ConnectionParameters(host='localhost'))
    
    channel = connection.channel()
    
    channel.queue_declare(queue='rpc_queue')
    
    
    def fib(n):
        if n == 0:
            return 0
        elif n == 1:
            return 1
        else:
            return fib(n - 1) + fib(n - 2)
    
    
    def on_request(ch, method, props, body):
        n = int(body)
        print(" [.] fib(%s)" % n)
        response = fib(n)
        print(" [.] calculated (%s)" % response)
    
        ch.basic_publish(exchange='',
                         routing_key=props.reply_to,
                         properties=pika.BasicProperties(correlation_id=props.correlation_id),
                         body=str(response))
        ch.basic_ack(delivery_tag=method.delivery_tag)
    
    
    channel.basic_qos(prefetch_count=1)
    channel.basic_consume(queue='rpc_queue', on_message_callback=on_request)
    
    print(" [x] Awaiting RPC requests")
    channel.start_consuming()
    

    以上2个是基于RabbitMQ的RPC教程。

    1. Dockerfile
    FROM python:3
    RUN mkdir code
    ADD flask_server.py requirements.txt /code/
    WORKDIR /code
    RUN pip install -r requirements.txt
    ENV FLASK_APP flask_server.py
    EXPOSE 5000
    CMD ["flask", "run", "-h", "0.0.0.0"]
    
    1. Docker-compose.yml
    services:
        web:
            build: .
            ports:
                - "5000:5000"
            links: rabbit
            volumes:
                - .:/code
        rabbit:
            hostname: rabbit
            image: rabbitmq:latest
            ports:
                - "5672:5672"
    

    运行 docker-compose up,Flask 服务器应该开始与 RabbitMQ 服务器通信。

    【讨论】:

    • 是否有理由总是在端点请求中创建新连接?用flask开始连接不是更好吗,还是我错过了什么?
    • 快速@Akalanka Weerasooriya,我正在构建一个类似的架构,我有点困惑,你愿意解释一下这个结构将如何在 Flask 中工作。为了接收和响应请求,worker 和 flask_server 将在哪里运行?
    【解决方案2】:

    RabbitMQ 服务器、worker 和 Dockerfile 的编写方式有很多种。
    第一个答案展示了它们的好例子。

    我只是强调 当工作人员(在您的情况下为 web 服务)将 尝试访问它时,RabbitMQ 服务器可能还没有准备好。
    为此我建议像这样编写docker-compose.yml 文件

    version: "3"
    
    services:
    
      web:
        build: .
        ports:
          - "5000:5000"
        restart: on-failure
        depends_on:
          - rabbitmq
        volumes:
          - .:/code
    
      rabbit:
        image: rabbitmq:latest
        expose:
          - 5672
        healthcheck:
          test: [ "CMD", "nc", "-z", "localhost", "5672" ]
          interval: 3s
          timeout: 10s
          retries: 3
    

    那么,我在这里做了什么?

    1) 我在web 服务中添加了depends_onrestart 属性,在rabbit 服务中添加了healthcheck 属性。
    现在 web 服务将自行重启,直到 rabbit 服务恢复正常。

    2) 在 rabbit 服务中,我使用了expose 属性而不是ports,因为在您的情况下,5672 端口需要在容器之间共享并且不需要公开给主人。

    来自Expose 文档:

    公开端口而不将它们发布到主机 - 它们会 只能被链接的服务访问。只有内部端口可以 指定。

    3) 我删除了links 属性,因为(取自here):

    链接不需要启用服务进行通信 - 默认情况下, 任何服务都可以通过该服务的名称访问任何其他服务。

    【讨论】:

      【解决方案3】:

      https://youtu.be/ZxVpsClqjdw 这个视频用代码解释了一切

      并且有一个 docker-compose as

      version: '3'
      
      services:  
      
        redis:
          image: redis:latest
          hostname: redis
      
        rabbit:
          hostname: rabbit
          image: rabbitmq:latest
          environment:
            - RABBITMQ_DEFAULT_USER=admin
            - RABBITMQ_DEFAULT_PASS=mypass
      
        web:
          build:
            context: .
            dockerfile: Dockerfile
          hostname: web
          command: ./scripts/run_web.sh
          volumes:
            - .:/app 
          ports:
            - "5000:5000"
          links:
            - rabbit
            - redis
      
        worker:
          build:
            context: .
            dockerfile: Dockerfile
          command: ./scripts/run_celery.sh
          volumes:
            - .:/app
          links:
            - rabbit
            - redis
          depends_on:
            - rabbit
      

      并建立连接使用

      BROKER_URL = 'amqp://admin:mypass@rabbit//'
      CELERY = Celery('tasks',backend=REDIS_URL,broker=BROKER_URL)
      

      进一步解释https://medium.com/swlh/dockerized-flask-celery-rabbitmq-redis-application-f317825a03b

      【讨论】:

        猜你喜欢
        • 2017-09-28
        • 2017-03-23
        • 2021-08-15
        • 1970-01-01
        • 2018-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-19
        相关资源
        最近更新 更多