Unix 域套接字的乐趣

2021-07-24 23:34:31

本周对 Datasette 的一个小改进:我添加了对通过 Unix 域套接字进行代理的支持。这最初是来自 Aslak Raanes 的功能请求:#1388:使用 UNIX 域套接字提供服务。我以前没有接触过这些,所以这是学习新东西的好机会。 Unix 域套接字提供了一种机制,机器上的不同进程可以通过类似于 TCP 的机制与每个进程进行通信,但通过文件路径代替。我之前在 Docker 守护进程中遇到过这些,它侦听路径 /var/run/docker.sock 并且可以像这样使用 curl 进行通信:如果单击“HTTP”选项卡,Docker 文档中有更多示例。事实证明,nginx 和 Apache 都能够将流量代理到 Unix 域套接字而不是 HTTP 端口,这使得它成为运行后端服务器而不将它们附加到 TCP 端口的有用机制。 Datasette 使用出色的 Uvicorn Python Web 服务器来提供开箱即用的流量,并且 Uvicorn 已经包含对 UDS 的支持——因此添加对 Datasette 的支持非常容易——这是完整的实现。我添加了一个新的 --uds 选项,所以现在你可以像这样运行 Datasette:

Datasette 将在 /tmp/datasette.sock 上“监听”——这意味着您可以像这样通过 curl 运行请求:更重要的是,这意味着您可以像这样配置 nginx 或 Apache 来代理到 Datasette 服务器(nginx): daemon off;事件 { worker_connections 1024;} http { 服务器 { 监听 80;位置 / { proxy_pass http://datasette; proxy_set_header 主机 $host; } } 上游数据集 { 服务器 unix:/tmp/datasette.sock; }} 实现只有几行代码(将 uds 选项传递给 Uvicorn)但添加测试证明更具挑战性。我使用这个 pytest 固定装置来启动服务器进程:@ pytest。夹具(范围 =“会话”)def ds_unix_domain_socket_server(tmp_path_factory):socket_folder = tmp_path_factory。 mktemp("uds") uds = str(socket_folder / "datasette.sock") ds_proc = subprocess. Popen( [ "datasette", "--memory", "--uds", uds], stdout = subprocess.PIPE, stderr = subprocess.STDOUT, cwd = tempfile.gettempdir(), ) #给服务器时间启动时间。 sleep( 1.5) # 检查是否成功启动 assert not ds_proc.民意调查(),ds_proc。标准输出。读()。 decode("utf-8") yield ds_proc, uds # 在 pytest 会话结束时关闭它 ds_proc. terminate() 我对其他一些测试使用了类似的模式,以练习 #1221 中添加的 --ssl-keyfile 和 --ssl-certfile 选项。测试本身看起来像这样,利用 HTTPX 对 Unix 域套接字进行调用的能力:

@pytest。标记。串行@pytest。标记。 skipif( not hasattr( socket, "AF_UNIX"), reason = "Requires socket.AF_UNIX support") def test_serve_unix_domain_socket(ds_unix_domain_socket_server): _, uds = ds_unix_domain_socket_server transport = httpx. HTTPTransport(uds = uds) 客户端 = httpx.客户端(传输 = 传输)响应 = 客户端。 get( "http://localhost/_memory.json") assert { "database": "_memory", "path": "/_memory", "tables": [], }. items() <= 响应。 json()。 items() skipif 装饰器避免在不支持 Unix 域套接字的平台上运行此测试(我认为包括 Windows,请参阅此评论)。 @pytest.mark.serial 装饰器应用了一个“标记”,可用于有选择地运行测试。我这样做是因为 Datasette 的测试使用 pytest-xdist 在 CI 中运行,但这与这种启动临时服务器的方式不兼容。 Datasette 实际上在 GitHub Actions 中运行测试,如下所示: - name: Run tests run: | pytest -n auto -m "not serial" pytest -m "serial" pytest -n auto -m "not serial" 行使用 pytest-xdist 在自动选择的进程数上运行几乎所有测试,但跳过那些用@pytest.mark.serial 标记。然后第二行在没有任何额外并发的情况下运行剩余的串行测试。可以在代理文档后面的运行数据集中找到此功能的文档和示例配置。感谢 Aslak 提供有关 Apache 配置的注释。