【问题标题】:Docker service needs to affect both replicas of another serviceDocker 服务需要影响另一个服务的两个副本
【发布时间】:2020-06-26 05:21:46
【问题描述】:

早上好,

我遇到了一个我正在努力诊断和解决的问题。首先声明一下,我大约 6 或 7 个月前才开始学习 Python,在此之前我没有任何开发经验。我的第一个项目是一个使用 Scrapy 引擎的网页抓取项目。在学习了 Docker 之后,我决定把它分解成容器。这需要一些时间才能弄清楚,但一旦我做到了,我就可以在 docker-compose.yml 中工作和协调。

我有 5 项服务,一项用于 Scrapyd,它是 Scrapy 引擎运行的守护程序/服务器,一项用于 postgres 收集抓取的条目,一项用于轮询 postgres 以查找关键字,还有一个 postgres 服务与之配套。最后,我有部署服务,这给我带来了麻烦。

部署服务等待 Scrapyd 服务完全启动(通过脚本中的 APi 调用验证),然后为我所有的蜘蛛(抓取数据的网络爬虫)构建 python egg 文件,并通过发布请求将它们发送到刮痧。这一切都可以正常工作,但是现在我正在尝试将其部署到 Docker Swarm 上。

我在 2 个 Raspberry Pi 上设置了我的 swarm 设置,我用它来部署 Scrapyd 服务

sudo docker service create --name scrapyd --network scrapy-bridge \
--publish 6800:6800 --hostname scrapyd --with-registry-auth \
--replicas 2 my-registry:test-scrapyd-arm

然后我启动部署服务:

sudo docker service create --name scrapyd-deploy --replicas 2 \
--network scrapy-bridge --with-registry-auth \
my-registry:test-scrapyd-deploy-arm

除了部署服务似乎只影响 Scrapyd 的副本之一之外,一切似乎都很顺利。当我通过发送多个运行蜘蛛的请求进行测试时,有些会通过,有些会返回蜘蛛不存在的错误。

然后我做了:

curl 127.0.0.1:6800

多次发现蜘蛛只部署到其中一个 Scrapyd 副本

如何进行设置,以便我的部署服务影响两个节点上的 Scrapyd 服务?

docker-compose.yml:

version: '3'
services:
    scrapyd:
        image: my-image:test-scrapyd
        ports:
            - "6800:6800"
        expose:
            - "6800"
        volumes:
            - Vscrapyd:/app/clist/
        networks: 
             - scrapyd-postgres
             - scrapy-bridge
            # - bridge

    scrapyd-postgres:
        image: my-image:test-scrapyd-postgres
        ports:
            - "5400:5432"
        depends_on: 
            - scrapyd
        volumes: 
            - Vscrapyd-postgres:/var/lib/postgresql/data
        networks: 
             - scrapyd-postgres
             - notify-bridge

    notify:
        image: my-image:test-notify
        depends_on: 
            - notify-postgres
        volumes: 
            - Vnotify:/projects/notify
        networks: 
             - notify-bridge
             - notif-postgres

    notify-postgres:
        image: my-image:test-notify-postgres
        ports: 
            - "5401:5432"
        depends_on: 
            - scrapyd-postgres
        volumes: 
            - Vnotify-postgres:/var/lib/postgresql/data
        networks: 
             - notif-postgres

    scrapyd-deploy:
        image: my-image:test-scrapyd-deploy
        volumes:
            - VTscrapyd-deploy:/app/clist_deploy/
        networks:
            - scrapy-bridge
        command: ["./entrypoint.sh", "scrapyd", "6800" , "python3", "/app/clist_deploy/deploy.py"]


volumes: 
    Vscrapyd:
        external: false
    Vscrapyd-postgres:
        external: false
    Vnotify:
        external: false
    Vnotify-postgres:
        external: false
    VTscrapyd-deploy:
        external: false
    Vscrapyd-api:
        external: false

networks:
    default:
        external:
            name: bridge
    notif-postgres:
        driver: bridge
        external: false
    scrapyd-postgres:
        driver: bridge
        external: false
    notify-bridge:
        driver: bridge
        external: false
    scrapy-bridge:
        driver: bridge
        external: false

入口点.sh

#!/bin/sh

set -e

host="$1"
port="$2"
shift 2
cmd="$@"

python3 scrapy_status.py $host $port

# Retrieves the server response and parses out ok if it exists in response
# if ok then breaks out of loop
# until [ $response = "ok" ]

exec $cmd

scrapy_status.py

import subprocess, sys, time


def get_scrapyd_status(host, port):

    try:
        result = subprocess.check_output(["curl",f"http://{host}:{port}/daemonstatus.json"])
    except subprocess.CalledProcessError:
        pass
    else:
        return result

def main(host,port):
    count = 0
    while (count < 5):
        r = get_scrapyd_status(host,port)

        print(r)
        try:
            r = "".join(map(chr,r)).split(",")[1].split(":")[1].replace('"',"").strip()
        except TypeError:
            pass
        if r == 'ok':
            print('Scrapyd is up!')
            sys.exit(0)
        else:
            print('Scrapyd not up yet...')
            pass
        count += 1
        time.sleep(5)

if __name__ == "__main__":
    if sys.argv and len(sys.argv) != 3:
        sys.exit('Only 2 arguments are allowed!')
    elif len(sys.argv) == 3:
        host = sys.argv[1]
        port = sys.argv[2]
        main(host,port)
    else:
        sys.exit('Unknown error ocurred')

这里有一个 gist 来 deploy.py 如果有人想看的话

【问题讨论】:

  • 可以添加docker-compose文件吗?
  • 添加了 docker-compose.yml entrypoint.sh 和 scrapy_status.py

标签: docker docker-compose scrapy


【解决方案1】:

您似乎正处于此项目中的某个阶段,您希望将其整合到生产部署中。首先,如果您在没有软件开发经验的情况下在 6 个月内学会了所有这些,那么您已经完成了出色的工作。

继续前进,您选择的工具以及它们之间的交互方式有一段历史在起作用。 Docker Swarm 是 Docker 本身的一部分,而 Docker Compose 是 Docker 外部的,通过 Docker API 与 Docker Engine 交互工作。实际上,Compose 只是一个 Python 脚本。如今,这两种工具有很多相似之处,并且在过去几年中逐渐增加了很多东西。

有趣的部分是当您开始考虑第三种工具时:Docker Stack。 Stack 和 Swarm 一样,是 Docker 的一部分。结合起来,这两个工具在很多方面与 Compose 重叠。它们都可以读取相同的 docker-compose.yml 文件(但 Stack 需要版本 3,而 Compose 也可以使用旧版本)。

Docker Stack 和 Docker Compose 的主要区别之一是后者会构建新的镜像。 Stack 希望预先构建图像,并将从那里协调设置过程。出于这个原因,到目前为止,Compose 仍然是您一直在使用它的最佳选择:本地开发和测试,其中图像作为开发周期的一部分被一遍又一遍地重建。

那么,我在这里得到什么?由于您开始考虑使用 swarm 部署此项目,因此可能也是考虑使用 Docker Stack 来帮助协调部署的好时机。您可以使用:

$ docker stack deploy

直接将堆栈部署到一个集群。首先,你需要添加一个注册服务:

$ docker service create --name registry --publish published=5000,target=5000 registry:2
$ curl http://localhost:5000/v2/

由于您已经构建了应用程序并使用 docker-compose 构建它,因此使用它构建它:

$ docker-compose up -d
[ wait.... ]
$ docker-compose down

推送到注册表:

$ docker-compose push

并尝试将其部署到堆栈:

$ docker stack deploy --compose-file docker-compose.yml stackdemo

this documentation 可能会有所帮助。您应该能够使用 Stack 来控制 swarm 中所有副本的设置。

【讨论】:

  • 非常感谢您回答这个问题,我正在设置这个,我必须在树莓派上安装 64 位操作系统才能使用 docker-compose(当我运行 docker-compose 之前在运行 ubuntu 服务器的旧笔记本电脑上)所以我还有一些工作要做。再次感谢!
猜你喜欢
  • 2019-10-19
  • 1970-01-01
  • 2018-11-03
  • 1970-01-01
  • 2018-11-08
  • 2018-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多