部署Python后鉴权失败

  1. 全程使用docker方式部署
  2. 本地采用非标准端口部署,即非标准80端口
  3. 运行python,print (“hello world”),正常反馈结果
  4. 尝试python, base.auth() 时,反馈错误,超时
from seatable_api import Base, context

base = Base(context.api_token, context.server_url)
base.auth()
  1. 查看本地日志,/python-pipeline/logs/scheduler-logs/nginx.error.log
[error] 754#754: *51 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.192.5, server: _, request: "GET /run-script/26/?dtable_uuid=d5b9a51d-1d9b-47a4-aa13-f361f5847045&script_name=W938.py HTTP/1.1", upstream: "http://[::1]:5055/run-script/26/?dtable_uuid=d5b9a51d-1d9b-47a4-aa13-f361f5847045&script_name=W938.py", host: "python-scheduler"

基本就是超时错误,怎么处理?
确认docker容器都运行了,网络也构建了

您好,您是在同一台服务器上部署的是吗?可以提供下相关 docker-compose.yml python-pipeline.yml 及 .env 文件吗?

同一台机上部署,都是docker镜像。按官方最新教程配的。
即:

附配置文件:
针对部署时使用的是非标准端口,对配置文件相应改8080端口,其他不变
具体地:

  1. docker-compose.yml
  • 8080:80 仅变更对外端口为8080,其余没变
  1. python-pipeline.yml
  • SEATABLE_SERVER_URL=${SEATABLE_SERVER_PROTOCOL}://${SEATABLE_SERVER_HOSTNAME}:8080
  1. env
    SEATABLE_SERVER_HOSTNAME=
    PYTHON_SCHEDULER_AUTH_TOKEN= 已设置UUID

  2. seatable-data/seatable/conf/dtable_web_settings.py 增加:
    SEATABLE_FAAS_URL = ‘http://python-scheduler
    SEATABLE_FAAS_AUTH_TOKEN = 一致的UUID

现在情况

  1. 正常的Py脚本可以运行,如helloworld,有输出正确结果
  2. 但是鉴权,auth(),执行会报错,超时

您配置中的 python-pipeline.yml 中的 SEATABLE_SERVER_URL 恢复为默认,去掉 :8080 试下

一样的错误。实际上,一开始就没有加8080,报超时错误。取不取消,效果一样。
从scheduler-logs上看到错误日志?

[error] 754#754: *77 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.240.5, server: _, request: “GET /run-script/54/?dtable_uuid=d5b9a51d-1d9b-47a4-aa13-f361f5847045&script_name=W938.py HTTP/1.1”, upstream: “http://[::1]:5055/run-script/54/?dtable_uuid=d5b9a51d-1d9b-47a4-aa13-f361f5847045&script_name=W938.py”, host: “python-scheduler”

base = Base(context.api_token, context.server_url)
改成 base = Base(api_token, server_url)试试

bro,你认真的吗?肯定会报错,变量未定义呀… 我输出过值的
context.api_token, context.server_url 这两个变量有正确值输出,没问题?

抱歉, 我看错了自己的脚本

你这个提示应该是seatable找不到python scheduler docker服务器

你看下docker 网络是不是正常的, 特别是seatable mysql python scheduler那三个docker 要在同一个docker网络, 因为内部通讯都是靠 ‘[http://python-scheduler ]来访问的

确认问题的根源:在于容器之间的网络连通问题

具体来说,py脚本运行依次涉及容器:seatable → python-scheduler → python-starter → python-runner
上述seatable → python-scheduler → python-starter,这三者的网络连通正常,都是挂载在 frontend-net 下的内部网络中。
而实际脚本是运行在runner容器中的,由starter创建运行销毁,所以闲时看不到
实际runner是挂载在 bridge 默认的内部网络中。
问题的具体原因,在于runner可以访问到seatable,但seatable回应不了runner。
临时的解决方法,将 seatable 也添加至 bridge 网络。这样,鉴权成功!
但是,反馈的消息,反馈的 seatable 服务器的IP是宿主机的(反正不是bridge的IP),所以导致无法下一步base的使用操作…(应该要配置?)

… 做到这!是不是哪一个关于网络的配置我搞错了呢?导致这个连锁问题?

现在的情况:

  1. 本地可以运行脚本,可以鉴权,可以操作表单(正常)
  2. 云端无法运行脚本。可以鉴权,但是无法继续base操作
    折衷方法,可以把鉴权部分的代码展开,就可以继续用了。这部分代码开源
    根本方法,还是要解决runner和seatable-server之间的网络

seatable python 内部部署

部署环境

  • 系统:Windows11内Ubuntu 20.04.6 LTS子系统
  • dtable_web_settings.py:DTABLE_WEB_SERVICE_URL='http://127.0.0.1/'
  • .env:PYTHON_STARTER_ALTERNATIVE_FILE_SERVER_ROOT=http://seatable

调整步骤

  • 容器:python-starter
  • 文件:runner.py
  • 步骤:在python-runner容器启动参数里指定下network,然后Base鉴权的时候server_url改用http://seatable
def run_python(data):
    ...原代码
    logging.debug("prepare the command to start the python runner")
    container_name = "python-runner" + tmp_id
    command = [
        "docker",
        "run",
        "--name",
        container_name,
        "--env-file",
        env_file,
        "-v",
        "{}:/scripts".format(tmp_dir),
        "--network=backend-seatable-net" # 指定容器网络
    ]
    logging.debug("command: %s", command)
  • 容器:seatable
  • 文件:/opt/seatable/seatable-server-latest/dtable-web/seahub/api2/endpoints/dtable_api_token.py
  • 步骤:引入re正则库,替换DTableAppAccessTokenView返回值中的链接
import re

class DTableAppAccessTokenView(APIView):
    throttle_classes = (AppRateThrottle,)

    def get(self, request):
        # 原代码
            
        host = request.build_absolute_uri().replace(request.path, '').strip("/") + "/"
        
        if host not in dtable_server_url:
            dtable_server_url = re.sub(r"https?://.*?/", host, dtable_server_url)
            dtable_socket_url = dtable_server_url
        if host not in DTABLE_DB_URL:
            dtable_db = re.sub(r"https?://.*?/", host, DTABLE_DB_URL)
        else:
            dtable_db = DTABLE_DB_URL

        return Response({
            'app_name': app_name,
            'access_token': access_token,
            'dtable_uuid': str(dtable.uuid),
            'dtable_server': dtable_server_url,
            'dtable_socket': dtable_socket_url,
            # 'dtable_db': DTABLE_DB_URL,
            'dtable_db': dtable_db,
            'workspace_id': workspace_id,
            'dtable_name': dtable.name,
            'use_api_gateway': True,
        })

  • python示例脚本
from seatable_api import Base, context

base = Base(context.api_token, 'http://seatable')
base.auth()
print(base)