mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-28 22:20:35 +00:00
Both shipped compose files used the floating nginx:alpine tag. When the
alias moved to the 1.31.3 alpine build (musl 1.2.6), nginx's pid-file
pwrite() started issuing pwritev2(RWF_NOAPPEND), which the default
seccomp profile of older Docker releases (and EOL kernels like CentOS 7)
does not allowlist. The master then dies with
pwrite() "/run/nginx.pid" failed (1: Operation not permitted)
and the container restart-loops, so make docker-start / make up never
become healthy. The image cannot fix this (nginx/docker-nginx#1059);
1.31.2 is the last alpine build on musl 1.2.5, whose pwrite() still uses
pwrite64.
Pins both compose files to nginx:1.31.2-alpine in lockstep and adds a
regression test that rejects any floating nginx tag in either file.
This commit is contained in:
parent
f79debed59
commit
a7d8971078
48
backend/tests/test_compose_nginx_image_pin.py
Normal file
48
backend/tests/test_compose_nginx_image_pin.py
Normal file
@ -0,0 +1,48 @@
|
||||
"""Regression test pinning the nginx image tag in the shipped compose files.
|
||||
|
||||
Both compose files deployed ``image: nginx:alpine`` — a floating tag. When the
|
||||
``nginx:alpine`` alias moved to the 1.31.3 alpine build (musl 1.2.6), nginx's
|
||||
pid-file ``pwrite()`` started issuing the ``pwritev2(RWF_NOAPPEND)`` syscall,
|
||||
which the default seccomp profile of older Docker releases (and EOL kernels
|
||||
such as CentOS 7) does not allowlist. The master then dies with ``pwrite()
|
||||
"/run/nginx.pid" failed (1: Operation not permitted)`` and the container
|
||||
restart-loops, so ``make docker-start`` / ``make up`` never become healthy
|
||||
(#7615; upstream nginx/docker-nginx#1059 — the image cannot fix this, only a
|
||||
pinned pre-musl-1.2.6 build or a host upgrade helps).
|
||||
|
||||
This test pins the exact-tag policy so the alias (or any other floating tag)
|
||||
cannot silently return.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
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",
|
||||
}
|
||||
|
||||
# An exact tag carries a full major.minor.patch; `alpine` / `latest` /
|
||||
# `1.31` style tags float and can re-resolve to a broken build overnight.
|
||||
EXACT_TAG = re.compile(r"^[^:]+:\d+\.\d+\.\d+(-[a-z]+)?$")
|
||||
|
||||
|
||||
def test_nginx_image_is_pinned_to_an_exact_tag() -> None:
|
||||
for name, compose_path in COMPOSE_PATHS.items():
|
||||
compose = yaml.safe_load(compose_path.read_text(encoding="utf-8"))
|
||||
image = (compose.get("services") or {}).get("nginx", {}).get("image")
|
||||
assert isinstance(image, str) and image, f"{name}: nginx service must declare an image"
|
||||
assert EXACT_TAG.match(image), f"{name}: nginx image {image!r} must pin an exact tag — a floating tag resolved to the musl-1.2.6 alpine build whose pwritev2 syscall older Docker seccomp profiles reject (#7615)"
|
||||
|
||||
|
||||
def test_both_compose_files_pin_the_same_nginx_image() -> None:
|
||||
images = set()
|
||||
for compose_path in COMPOSE_PATHS.values():
|
||||
compose = yaml.safe_load(compose_path.read_text(encoding="utf-8"))
|
||||
images.add((compose.get("services") or {}).get("nginx", {}).get("image"))
|
||||
assert len(images) == 1, "prod and dev compose files must pin the same nginx image"
|
||||
@ -123,7 +123,13 @@ services:
|
||||
# ── Reverse Proxy ──────────────────────────────────────────────────────
|
||||
# Routes API traffic to gateway and (optionally) provisioner.
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
# Pinned tag, not `nginx:alpine`: from 1.31.3 the alpine builds ship musl
|
||||
# 1.2.6, whose pwrite() issues pwritev2(RWF_NOAPPEND) — seccomp profiles
|
||||
# on older Docker/EOL kernels reject that syscall and the master dies in a
|
||||
# restart loop with `pwrite() "/run/nginx.pid" failed (1: Operation not
|
||||
# permitted)` (#7615, nginx/docker-nginx#1059). 1.31.2 is the last musl
|
||||
# 1.2.5 (pwrite64) alpine build. Keep in lockstep with docker-compose.yaml.
|
||||
image: nginx:1.31.2-alpine
|
||||
container_name: deer-flow-nginx
|
||||
# Loopback-only by default; see the note in docker-compose.yaml. Override
|
||||
# with BIND_HOST when you deliberately need the dev stack reachable from
|
||||
|
||||
@ -50,7 +50,13 @@ services:
|
||||
|
||||
# ── Reverse Proxy ──────────────────────────────────────────────────────────
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
# Pinned tag, not `nginx:alpine`: from 1.31.3 the alpine builds ship musl
|
||||
# 1.2.6, whose pwrite() issues pwritev2(RWF_NOAPPEND) — seccomp profiles
|
||||
# on older Docker/EOL kernels reject that syscall and the master dies in a
|
||||
# restart loop with `pwrite() "/run/nginx.pid" failed (1: Operation not
|
||||
# permitted)` (#7615, nginx/docker-nginx#1059). 1.31.2 is the last musl
|
||||
# 1.2.5 (pwrite64) alpine build.
|
||||
image: nginx:1.31.2-alpine
|
||||
container_name: deer-flow-nginx
|
||||
# Loopback-only by default: DeerFlow's agent can execute commands, so the
|
||||
# documented default deployment is a local trusted environment. A bare
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user