diff --git a/CHANGELOG.md b/CHANGELOG.md index e0e4b1035c..dfefa9b9e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -323,6 +323,14 @@ This release closes that milestone with **181 merged pull requests**. ### Fixed +- **docker:** The production stack (`make up` / `scripts/deploy.sh`) now starts + on hosts with IPv6 disabled. `docker/nginx/nginx.conf` also listens on + `[::]:2026`; on a kernel booted with `ipv6.disable=1` that listen makes nginx + exit at startup, so the container restart-looped and `make up` never became + healthy. The dev compose file has stripped the IPv6 listen when + `/proc/net/if_inet6` is absent since #2027, and the Helm chart mirrors it; + the production compose file was the one launcher still without the guard. + It now uses the same launcher, and starts nginx with `exec` so it is PID 1. ([#5900]) - **skills:** `skill_manage(action="remove_file")` and `write_file` now work on binary support files, and reject directories cleanly. A `.skill` archive may carry `assets/logo.png` (the installer only rejects *executable* binaries), @@ -6120,4 +6128,5 @@ with **180 merged pull requests** since the first 2.0 milestone tag. [#5879]: https://github.com/bytedance/deer-flow/pull/5879 [#5881]: https://github.com/bytedance/deer-flow/pull/5881 [#5893]: https://github.com/bytedance/deer-flow/pull/5893 +[#5900]: https://github.com/bytedance/deer-flow/pull/5900 diff --git a/CHANGELOG_zh.md b/CHANGELOG_zh.md index bca5d78285..88fc98341f 100644 --- a/CHANGELOG_zh.md +++ b/CHANGELOG_zh.md @@ -328,6 +328,12 @@ ### 修复 +- **Docker:** 生产栈(`make up` / `scripts/deploy.sh`)现在可以在禁用 IPv6 的主机上启动。 + `docker/nginx/nginx.conf` 同时监听 `[::]:2026`;在以 `ipv6.disable=1` 启动的内核上,这条监听会让 + nginx 在启动时退出,容器因此反复重启,`make up` 永远无法就绪。开发用 compose 文件自 #2027 起 + 会在 `/proc/net/if_inet6` 不存在时去掉 IPv6 监听,Helm chart 也做了同样处理;生产用 compose + 文件是唯一还没有这层保护的启动器。现在它使用相同的启动脚本,并以 `exec` 启动 nginx 使其成为 + PID 1。([#5900]) - **技能:** `skill_manage(action="remove_file")` 与 `write_file` 现在可以处理二进制支持文件, 并会干净地拒绝目录。`.skill` 压缩包可以包含 `assets/logo.png`(安装器只拒绝*可执行*二进制), 但这两个操作在改动文件之前会先把原有内容按 UTF-8 文本读出(仅用于历史记录),于是二进制 @@ -5205,3 +5211,4 @@ DeerFlow 2.0 是围绕"超级智能体"框架的彻底重写,核心包含子 [#5879]: https://github.com/bytedance/deer-flow/pull/5879 [#5881]: https://github.com/bytedance/deer-flow/pull/5881 [#5893]: https://github.com/bytedance/deer-flow/pull/5893 +[#5900]: https://github.com/bytedance/deer-flow/pull/5900 diff --git a/backend/tests/test_compose_nginx_ipv6_guard.py b/backend/tests/test_compose_nginx_ipv6_guard.py new file mode 100644 index 0000000000..9b4e12e7ff --- /dev/null +++ b/backend/tests/test_compose_nginx_ipv6_guard.py @@ -0,0 +1,115 @@ +"""Every nginx launcher must survive a host with IPv6 disabled. + +``docker/nginx/nginx.conf`` listens on both ``2026`` and ``[::]:2026``. On a +host booted with ``ipv6.disable=1`` (or a kernel without IPv6) nginx refuses to +start — ``socket() [::]:2026 failed (97: Address family not supported by +protocol)`` — and a ``restart: unless-stopped`` container loops until the +``--wait`` readiness check gives up. #2027 added a launcher guard that strips +the IPv6 ``listen`` when ``/proc/net/if_inet6`` is absent, but only to the dev +compose file; the Helm chart mirrors it; the production compose file used by +``make up`` / ``scripts/deploy.sh`` did not. These tests pin the guard in every +launcher, keep the three copies identical, and check the pattern really +removes the IPv6 line from the config it is applied to. +""" + +from __future__ import annotations + +import re +from pathlib import Path + +import pytest +import yaml + +REPO_ROOT = Path(__file__).resolve().parents[2] +COMPOSE_PATHS = { + "prod": REPO_ROOT / "docker" / "docker-compose.yaml", + "dev": REPO_ROOT / "docker" / "docker-compose-dev.yaml", +} +HELM_NGINX_DEPLOYMENT = REPO_ROOT / "deploy" / "helm" / "deer-flow" / "templates" / "nginx-deployment.yaml" +NGINX_CONFS = { + "compose": REPO_ROOT / "docker" / "nginx" / "nginx.conf", + "helm": REPO_ROOT / "deploy" / "helm" / "deer-flow" / "templates" / "configmap-nginx.yaml", +} + +GUARD_RE = re.compile(r"test -e /proc/net/if_inet6 \|\| sed -i '(?P[^']+)' (?P\S+)") + + +def _compose_nginx_script(compose_path: Path) -> str: + compose = yaml.safe_load(compose_path.read_text(encoding="utf-8")) + command = compose["services"]["nginx"]["command"] + if isinstance(command, list): + assert command[:2] == ["sh", "-c"], f"{compose_path.name}: nginx command must be `sh -c