fix(helm): make the gateway init containers' image and resources conf… (#8161)

* fix(helm): make the gateway init containers' image and resources configurable

init-home and init-extensions hard-coded busybox:1.36 and set no resources.
Clusters that pull only from a mirror could not start the gateway, and a
namespace ResourceQuota on limits.* rejected the pod, although every main
container already has a configurable image and requests+limits.

Add gateway.initContainers.image (repository/tag, default busybox:1.36, same
convention as nginx.image) and gateway.initContainers.resources (modest
requests+limits by default, matching the chart README's resource defaults).
Add a helm-template test for the defaults and the overrides.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(helm): explain mirroring gateway init images

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
Bas Cancrinus 2026-11-12 09:44:42 +01:00 committed by GitHub
parent 2dc68b242f
commit 7ae36b469d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 93 additions and 3 deletions

View File

@ -0,0 +1,51 @@
"""The gateway's init containers must follow the chart's image and resource values.
``init-home`` and ``init-extensions`` hard-coded ``busybox:1.36`` and set no
resources. Clusters that pull only from a mirror could not start the gateway, and
a namespace ResourceQuota on ``limits.*`` rejected the pod, while every main
container already has configurable images and requests+limits.
"""
from __future__ import annotations
import shutil
import subprocess
from pathlib import Path
import pytest
import yaml
REPO_ROOT = Path(__file__).resolve().parents[2]
CHART = REPO_ROOT / "deploy" / "helm" / "deer-flow"
def _init_containers(*settings: str) -> list[dict]:
helm = shutil.which("helm")
if helm is None:
pytest.skip("helm is unavailable")
command = [helm, "template", "deer-flow", str(CHART)]
for setting in settings:
command.extend(["--set", setting])
rendered = subprocess.run(command, check=True, capture_output=True, text=True, encoding="utf-8").stdout
gateways = [document for document in yaml.safe_load_all(rendered) if isinstance(document, dict) and document.get("kind") == "Deployment" and document["metadata"]["name"].endswith("-gateway")]
assert len(gateways) == 1
init_containers = gateways[0]["spec"]["template"]["spec"]["initContainers"]
assert [container["name"] for container in init_containers] == ["init-home", "init-extensions"]
return init_containers
def test_init_containers_keep_busybox_with_requests_and_limits_by_default() -> None:
for container in _init_containers():
assert container["image"] == "busybox:1.36"
assert set(container["resources"]) == {"requests", "limits"}
assert set(container["resources"]["limits"]) == {"cpu", "memory"}
def test_init_containers_use_configured_image_and_resources() -> None:
for container in _init_containers(
"gateway.initContainers.image.repository=registry.example.com/mirror/busybox",
"gateway.initContainers.image.tag=1.36.1",
"gateway.initContainers.resources.limits.memory=32Mi",
):
assert container["image"] == "registry.example.com/mirror/busybox:1.36.1"
assert container["resources"]["limits"]["memory"] == "32Mi"

View File

@ -119,6 +119,21 @@ secrets:
# add channel tokens, search keys, etc. as needed
```
`image.registry` prefixes the DeerFlow gateway, frontend, and provisioner
images. In a cluster that pulls only from a mirror, set the full BusyBox
repository for `init-home` and `init-extensions` in the same values file.
```yaml
gateway:
initContainers:
image:
repository: registry.example.com/mirror/busybox
tag: "1.36"
```
Set `nginx.image.repository`, `postgresql.image.repository`, and
`redis.image.repository` separately for the corresponding bundled services.
The default ingress annotations permit a 100 MiB local `.skill` archive plus
multipart framing, stream request bodies without ingress buffering, and allow
up to 600 seconds for a response, which the API requests that wait on a model
@ -485,7 +500,8 @@ triggers a rolling restart.
**Resource defaults.** Every workload ships with modest requests+limits in
`values.yaml`; override per workload (`gateway.resources`, `frontend.resources`,
`nginx.resources`, `provisioner.resources`, `postgresql.primary.resources`,
`redis.primary.resources`).
`redis.primary.resources`). The gateway's init containers have their own
`gateway.initContainers.resources` and `gateway.initContainers.image`.
### Not yet enforced (deferred hardening)

View File

@ -59,6 +59,11 @@ imagePullSecrets:
{{- printf "%s:%s" .Values.nginx.image.repository .Values.nginx.image.tag -}}
{{- end -}}
{{/* Image of the gateway's init containers (init-home, init-extensions). */}}
{{- define "deer-flow.initImage" -}}
{{- printf "%s:%s" .Values.gateway.initContainers.image.repository .Values.gateway.initContainers.image.tag -}}
{{- end -}}
{{/* PVC name for the .deer-flow home directory. */}}
{{- define "deer-flow.homePVC" -}}
{{- printf "%s-home" (include "deer-flow.fullname" .) -}}

View File

@ -51,17 +51,19 @@ spec:
# API updates land in the home volume (PVC or pod-local emptyDir).
initContainers:
- name: init-home
image: busybox:1.36
image: {{ include "deer-flow.initImage" . }}
command: ["sh", "-c", "mkdir -p /home-pvc/deer-flow/data /home-pvc/deer-flow/extensions-config"]
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
resources:
{{- toYaml .Values.gateway.initContainers.resources | nindent 12 }}
volumeMounts:
- name: home
mountPath: /home-pvc
- name: init-extensions
image: busybox:1.36
image: {{ include "deer-flow.initImage" . }}
command: ["sh", "-c"]
args:
- |
@ -73,6 +75,8 @@ spec:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
resources:
{{- toYaml .Values.gateway.initContainers.resources | nindent 12 }}
volumeMounts:
- name: extensions-seed
mountPath: /extensions-seed

View File

@ -104,6 +104,20 @@ gateway:
limits:
cpu: "2"
memory: 2Gi
# Init containers (init-home, init-extensions) that prepare the home volume
# before the gateway starts. Point `image` at a mirror if your nodes cannot
# pull from Docker Hub.
initContainers:
image:
repository: busybox
tag: "1.36"
resources:
requests:
cpu: 10m
memory: 16Mi
limits:
cpu: 100m
memory: 64Mi
# -- Frontend (Next.js) deployment.
frontend: